28

Is there a way to pass variables using attributes to a directive without creating a new scope ?

HTML

<div ng-click='back()' button='go back'></div>

JS

.directive('button', function () {
    return {
        scope: {
            button: '@'
        },
        template: "<div><div another-directive></div>{{button}}</div>",
        replace: true
    }
})

The problem is that the ng-click='back()' now refers to the directive scope. I still can do ng-click='$parent.back()' but it's not what I want.

Seb Fanals
  • 645
  • 1
  • 6
  • 14
  • you should be using &attr to call parent functions passed as attribute http://stackoverflow.com/questions/15991137/calling-method-of-parent-controller-from-a-directive-in-angularjs/15991525 – Ajay Beniwal May 15 '13 at 09:40
  • I would like have a generic way. Not `scope: {back: '&'}` if it's what you mean ? To be able to do: `
    ` for another example.
    – Seb Fanals May 15 '13 at 10:08

2 Answers2

34

By default, directives do not create a new scope. If you want to make that explicit, add scope: false to your directive:

<div ng-click='back()' button='go back!'></div>
angular.module('myApp').directive("button", function () {
    return {
        scope: false,  // this is the default, so you could remove this line
        template: "<div><div another-directive></div>{{button}}</div>",
        replace: true,
        link: function (scope, element, attrs) {
           scope.button = attrs.button;
        }
    };
});

fiddle

Since a new property, button, is being created on the scope, you should normally create a new child scope using scope: true as @ardentum-c has in his answer. The new scope will prototypially inherit from the parent scope, which is why you don't need to put $parent.back() into your HTML.

One other tidbit to mention: even though we are using replace: true, clicking the element still calls back(). That works because "the replacement process migrates all of the attributes / classes from the old element to the new one." -- directive doc
So ng-click='back()' button='go back!' are migrated to the first div in the directive's template.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • You're right but I need the isolated scope to have multiple buttons with different names. Bad formulated question I guess. http://jsfiddle.net/gHjU4/2/ – Seb Fanals May 15 '13 at 17:29
  • OK now I'm feeling dumb, as you said, `scope:true` and no compile needed. I changed the accepted answer. – Seb Fanals May 15 '13 at 17:34
3

I guess you should use compile function in this case.

angular.module('myApp').directive("button", function () {
    return {
        template: "<div><div another-directive></div>{{button}}</div>",
        replace: true,
        scope:   true,
        compile: function (tElement, tAttrs) {
            // this is link function
            return function (scope) {
                scope.button = tAttrs.button;
            };            
        }
    };
});

Here is jsfiddle example.

ardentum-c
  • 1,410
  • 13
  • 11
  • I never used compile before but I saw it in the docs, should of read it. Thanks ! – Seb Fanals May 15 '13 at 10:38
  • 1
    `scope: true` creates a new scope. While I think this is the correct way to do it, the OP asked for no new scope. Also, a compile function is not necessary, only a link function. See my answer for more info. – Mark Rajcok May 15 '13 at 15:32