Nos casos em que você possui várias diretivas em um único elemento DOM e em que a ordem na qual elas são aplicadas é importante, você pode usar a priority
propriedade para solicitar a aplicação. Números mais altos correm primeiro. A prioridade padrão é 0 se você não especificar uma.
EDIT : após a discussão, aqui está a solução completa de trabalho. A chave era remover o atributo : element.removeAttr("common-things");
e também element.removeAttr("data-common-things");
(no caso de usuários especificar data-common-things
no HTML)
angular.module('app')
.directive('commonThings', function ($compile) {
return {
restrict: 'A',
replace: false,
terminal: true, //this setting is important, see explanation below
priority: 1000, //this setting is important, see explanation below
compile: function compile(element, attrs) {
element.attr('tooltip', '{{dt()}}');
element.attr('tooltip-placement', 'bottom');
element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html
return {
pre: function preLink(scope, iElement, iAttrs, controller) { },
post: function postLink(scope, iElement, iAttrs, controller) {
$compile(iElement)(scope);
}
};
}
};
});
Plunker de trabalho está disponível em: http://plnkr.co/edit/Q13bUt?p=preview
Ou:
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 the attribute to avoid indefinite loop
element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html
$compile(element)(scope);
}
};
});
DEMO
Explicação por que precisamos definir terminal: true
e priority: 1000
(um número alto):
Quando o DOM estiver pronto, o angular percorre o DOM para identificar todas as diretivas registradas e compilar as diretivas uma a uma com base em priority
se essas diretivas estão no mesmo elemento . Definimos a prioridade de nossa diretiva personalizada como um número alto para garantir que ela seja compilada primeiro e com terminal: true
as outras diretivas serão ignoradas após a compilação dessa diretiva.
Quando nossa diretiva personalizada é compilada, ela modifica o elemento adicionando diretivas e removendo-se e usa o serviço $ compile para compilar todas as diretivas (incluindo aquelas que foram ignoradas) .
Se não definirmos terminal:true
e priority: 1000
, há uma chance de que algumas diretivas sejam compiladas antes da nossa diretiva personalizada. E quando nossa diretiva personalizada usa $ compile para compilar o elemento => compile novamente as diretivas já compiladas. Isso causará um comportamento imprevisível, especialmente se as diretivas compiladas antes de nossa diretiva personalizada já tiverem transformado o DOM.
Para mais informações sobre prioridade e terminal, consulte Como entender o `terminal` da diretiva?
Um exemplo de diretiva que também modifica o modelo é ng-repeat
(prioridade = 1000), quando ng-repeat
é compilado, ng-repeat
faz cópias do elemento do modelo antes que outras diretivas sejam aplicadas .
Graças ao comentário de @ Izhaki, aqui está a referência ao ngRepeat
código-fonte: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js
RangeError: Maximum call stack size exceeded
enquanto continua compilando para sempre.