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 option
s.
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