简体   繁体   中英

Using an ngClass Directive Inside Another Directive Throws Console Error

I am trying to use ngClass inside my directive, and it is working but I am seeing a console error:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

Here is a simplified version of my directive which reproduces the issue:

angular.module('myApp', [])
    .directive('myDirective', function () {
    return {
        restrict: 'E',
        scope: {
            myNgClass: '='
        },
        template: '<div ng-class="myNgClass">Hello World</div>'
    }
});

And here is how I am using it:

<my-directive my-ng-class="{'green':true}"></my-directive>

And here is a link to a jsFiddle.

So, first of all, this error is specific to the version of Angular that you are using (v1.2.1) - it was fixed in v1.2.5 ( working demo with v1.2.5).

Second, you really shouldn't be using a two-way binding ( "=" ) since you don't seem to need to change the value from inside the directive. Using "=" unnecessarily creates 2 watchers.

You could definitely do one-way string binding ( "@" ), like so:

scope: {
  myNgClass: '@'
},
template: '<div ng-class="{{myNgClass}}">Hello World</div>'

but this will have a more limited use. For example you won't be able to pass a object ( $scope.greenStyle = { green: true }; ) to your directive:

<my-directive my-ng-class="greenStyle"></my-directive>

It is better to use a one-way binding to expressions - "&" . This keeps a single watch and binds to an object - not string. scope.myNgClass becomes a function that returns the value of the bound expression:

scope: {
  myNgClass: '&'
},
template: '<div ng-class="myNgClass()">Hello World</div>'

Demo

Use @ instead of = .

myNgClass: '@'

When you use = angular adds a $watch for changes to 'myNgClass'. When a $watch is added, angular adds $$hashKey to the object and "attempts" to assign the modified object back to where it came from (so that the source and destination have the same object).

The problem is when the $digest compares the object it has {'green':'true', $$hashKey: '123546246'} vs the evaluated expression {'green':'true'} the comparison fails so the $watch listener is run (NOTE: That part is just my theory. I don't know 100% that it's adding a hashKey, but i DO know that it's treating the objects as different instances and that's triggering the watch listener). Since my-ng-class will always send back a new instance of that object it will always be different and will always trigger the watch listener.

If you want to keep using = you can (but there's no need). You just have to define your initial object once elsewhere before passing it in. You can use ng-init to do that, like this:

<my-directive ng-init="clazz={'green':'true'}" my-ng-class="clazz"></my-directive>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM