问题
I'm trying to create a directive that's used like this:
<amount value="myValue" neg-class="negative" />
myValue
is a scope value (should be a number)
negative
is simply the name of a css class.
The idea behind the directive is that I wan't to show currency to the user and when the amount that's bound is negative, negClass get's applied to the rendered element.
The problem I'm having is that when negClass is changed, the update doesn't take effect. I do see the changes in the DOM, though.
Here's my directive definition:
myModule.directive('amount', function () {
return {
restrict: 'E',
replace: true,
template: '<span ng-class="{ {{negClass}}: value < 0 }">{{value | currency}}</span>',
scope: {
value: "=",
negClass: "@",
}
};
});
Here's a test harness that demonstrates the problem: https://dl.dropboxusercontent.com/u/1563210/amtdirtest.html
回答1:
Most of the angular directives tend to work in this way. Unless the docs specifically mention supporting interpolation ({{...}}
) for inputs then it's safer to not rely on it, especially where the input is an = rather than an @ binding.
In the case of ngClass, the attribute works like a = binding, and there is no mention of interpolation.
What actually happens in the directive is that the attribute is only observed in the linking phase and the the actual text in the attribute is never looked at again. So while the attribute continues to change, the changes are never seen.
By the time the attribute is seen by ngClass
, it looks something like
{ n: value < 0 }
which is still evaluated based on whatever the current value
is in scope, but the expression itself never gets changed again.
The safe way to do what you are trying would be to create an object without using interpolation, or to just have a function that returns which class is active...Something like the following should work:
myModule.directive('amount', function () {
return {
restrict: 'E',
replace: true,
template: '<span ng-class="getActiveClass()">{{value | currency}}</span>',
scope: {
value: "=",
negClass: "@",
},
link: function(scope, element, attrs) {
scope.getActiveClass = function() {
if(scope.value < 0)
return scope.negClass;
}
}
};
});
回答2:
Originally hadn't noticed that css was in the scope already.
Here's an approach that compiles the element dynamically using $compile
and $watch
to listen for changes in negClass
.directive('amount', function($compile) {
var template='<span ng-class="{ {{negClass}}: value < 0 }">{{value | currency}}</span>'
return {
restrict: 'E',
replace: true,
scope: {
value: "=",
negClass: "@",
},
link:function(scope,elem,attrs){
scope.$watch('negClass',function(){
elem.html('').append($compile(template)(scope) )
})
}
};
});
DEMO
来源:https://stackoverflow.com/questions/20456057/ng-class-within-custom-directive-not-observing-updates