javascript - Add directives from directive in AngularJS -
i'm trying build directive takes care of adding more directives element declared on. example, want build directive takes care of adding datepicker, datepicker-language , ng-required="true".
if try add attributes , use $compile generate infinite loop, checking if have added needed attributes:
angular.module('app') .directive('superdirective', function ($compile, $injector) { return { restrict: 'a', replace: true, link: function compile(scope, element, attrs) { if (element.attr('datepicker')) { // check return; } element.attr('datepicker', 'somevalue'); element.attr('datepicker-language', 'en'); // more $compile(element)(scope); } }; }); of course, if don't $compile element, attributes set directive won't bootstrapped.
is approach correct or doing wrong? there better way achieve same behavior?
udpate: given fact $compile way achieve this, there way skip first compilation pass (the element may contain several children)? maybe setting terminal:true?
update 2: have tried putting directive select element and, expected, compilation runs twice, means there twice number of expected options.
in cases have multiple directives on single dom element , order in they’re applied matters, can use priority property order application. higher numbers run first. default priority 0 if don’t specify one.
edit: after discussion, here's complete working solution. key remove attribute: element.removeattr("common-things");, , element.removeattr("data-common-things"); (in case users specify data-common-things in html)
angular.module('app') .directive('commonthings', function ($compile) { return { restrict: 'a', replace: false, terminal: true, //this setting important, see explanation below priority: 1000, //this setting important, see explanation below compile: function compile(element, attrs) { element.attr('tooltip', '{{dt()}}'); element.attr('tooltip-placement', 'bottom'); element.removeattr("common-things"); //remove attribute avoid indefinite loop element.removeattr("data-common-things"); //also remove same attribute data- prefix in case users specify data-common-things in html return { pre: function prelink(scope, ielement, iattrs, controller) { }, post: function postlink(scope, ielement, iattrs, controller) { $compile(ielement)(scope); } }; } }; }); working plunker available at: http://plnkr.co/edit/q13but?p=preview
or:
angular.module('app') .directive('commonthings', function ($compile) { return { restrict: 'a', replace: false, terminal: true, priority: 1000, link: function link(scope,element, attrs) { element.attr('tooltip', '{{dt()}}'); element.attr('tooltip-placement', 'bottom'); element.removeattr("common-things"); //remove attribute avoid indefinite loop element.removeattr("data-common-things"); //also remove same attribute data- prefix in case users specify data-common-things in html $compile(element)(scope); } }; }); explanation why have set terminal: true , priority: 1000 (a high number):
when dom ready, angular walks dom identify registered directives , compile directives 1 one based on priority if these directives on same element. set our custom directive's priority high number ensure compiled first , terminal: true, other directives skipped after directive compiled.
when our custom directive compiled, modify element adding directives , removing , use $compile service compile directives (including skipped).
if don't set terminal:true , priority: 1000, there chance directives compiled before our custom directive. , when our custom directive uses $compile compile element => compile again compiled directives. cause unpredictable behavior if directives compiled before our custom directive have transformed dom.
for more information priority , terminal, check out how understand `terminal` of directive?
an example of directive modifies template ng-repeat (priority = 1000), when ng-repeat compiled, ng-repeat make copies of template element before other directives applied.
thanks @izhaki's comment, here reference ngrepeat source code: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngrepeat.js
Comments
Post a Comment