问题
I'm trying to build a directive that change loading status on buttons for slow ajax calls. Basically the idea is to set an attribute "ng-loading" to a button element, and let the directive add the rest of stuff.
This is the html code:
<button class="btn btn-primary" name="commit" type="submit" ng-loading="signupLoading">
Submit
</button>
And this is the directive code:
.directive('ngLoading', ['$compile', function($compile) {
return {
restrict: 'A',
replace: false,
terminal: true,
link: function(scope, element, attrs) {
element.attr('ng-class', '{loading:' + attrs['ngLoading'] +'}');
element.attr('ng-disabled', attrs['ngLoading']);
element.append(angular.element('<img class="loading-icon" src="/assets/images/loading-icon.gif"/>'));
$compile(element.contents())(scope);
}
};
}]);
It all looks correct in the rendered HTML, but the attributes added from the directive is not funcioning at all. I can move those attributes to the HTML code and everything works great, but that's quite some redundant code in many places.
I referenced the post Angular directive to dynamically set attribute(s) on existing DOM elements but it does not solve my problem.
Any comment/suggestion are welcome. Thanks in advance.
回答1:
You don't need to recompile that directive if all you want is some DOM manipulation, you can add and remove class in regards to the changes of a scope property. You can use $watch instead.
JAVASCRIPT
.directive('ngLoading', function() {
return function(scope, element, attrs) {
var img = angular.element('<img class="loading-icon" src="/assets/images/loading-icon.gif"/>');
element.append(img);
scope.$watch(attrs.ngLoading, function(isLoading) {
if(isLoading) {
img.removeClass('ng-hide');
element.addClass('loading');
element.attr('disabled', '');
} else {
img.addClass('ng-hide');
element.removeClass('loading');
element.removeAttr('disabled');
}
});
};
});
Note: Your code doesn't work because it compiles the contents of the elements, not the element itself, where you attach the attributes you have implemented.
try $compile(elem)(scope);
and it should work properly, but I don't recommend it because each element with such directive will have to re-compile again.
UPDATE:
before using $compile
remove the attribute 'ngLoading' to the element to prevent infinite compilation.
elem.removeAttr('ng-loading');
$compile(elem)(scope);
来源:https://stackoverflow.com/questions/24987784/dynamically-add-angular-attributes-to-an-element-from-a-directive