Dmitry Belaventsev
Dmitry Belaventsev

Reputation: 6657

Angular directive code changes scope, but template shows the same value

I have a directive like the following:

.directive('myDirective', function() {
    return {
        restrict: 'AE',
        replace: true,
        templateUrl: '/myDirective.html?v=' + window.buildNumber,
        link: function (scope, element, attrs) {
            scope.itemClasses = attrs.itemClasses || '';
        }
    }
})

and it's template looks like:

<div class="my-directive">
    <div class="items" ng-repeat="item in items">
        <div class="item {{ itemClasses }}">{{ item.title }}</div>
    </div>
</div>

and that directive is called in different places (one call per template) like this:

<my-directive item-classes="col-md-6"></my-directive>
...
<my-directive item-classes="col-md-12"></my-directive>

And all templates render the same value of itemClasses. At the same time link function sets proper value (I checked this fact by call of console.log()).

And if I add scope: true attribute to the directive's code - then all works fine. So, it seems like having own inherited scope helps. Could you explain me such behaviour?

Thank you.

Upvotes: 0

Views: 149

Answers (2)

lenilsondc
lenilsondc

Reputation: 9810

By binding the item-classes directly from the attributes you are basically making a copy of the attribute's values.

The solution for this is: if you want to make input-classes an input binding you may use isolated scope like so:

{
    restrict: 'AE',
    replace: true,
    scope: {
        itemClasses: '='
    },
    templateUrl: '/myDirective.html?v=' + window.buildNumber,
    link: function (scope, element, attrs) {
        // scope.itemClasses = attrs.itemClasses || '';
    }
}

Or just in case you don't want to use isolated scope, you can user attrs.$observe:

link: function (scope, element, attrs) {
    attrs.$observe('itemClasses ', function(val) {
        scope.itemClasses = val || '';
    });
}

Upvotes: 1

quirimmo
quirimmo

Reputation: 9998

When you use scope: true you create a child scope for your directive and at the same time you inherit also the properties from the parent (in this case I think your controller). So all your directive's instances will have their proper scope.

Using scope: false your directive actually has no scope, and it shares the scope with its parent.

So, coming back to your question, having scope:false, when you do this:

scope.itemClasses = attrs.itemClasses || '';

you are setting the itemClasses property to the scope of the parent. It means that when you see in the link function it seems to work fine, but in reality every time you are going to override the same scope variable of the controller.

So, in your case, the first time you associate a scope variable to the parent controller:

scope.itemClasses= 'col-md-6';

but the second time actually you override the same scope variable of the parent with the new value:

scope.itemClasses= 'col-md-12';

Does it make sense?

Upvotes: 1

Related Questions