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.element.removeAttr("common-datepicker");
para evitar loop indefinido.replace: false
,terminal: true
,priority: 1000
; defina os atributos desejados nacompile
função e remova o atributo de diretiva. Finalmente, napost
função retornada porcompile
, chame$compile(element)(scope)
. O elemento será compilado regularmente sem a diretiva personalizada, mas com os atributos adicionados. O que eu estava tentando alcançar não era remover a diretiva personalizada e lidar com tudo isso em um processo: parece que isso não pode ser feito. Consulte a plnkr atualizada: plnkr.co/edit/Q13bUt?p=preview .common-things
atributos, você pode passar um parâmetro maxPriority para o comando compile:$compile(element, null, 1000)(scope);
Na verdade, você pode lidar com tudo isso com apenas uma tag de modelo simples. Veja http://jsfiddle.net/m4ve9/ para um exemplo. Observe que eu realmente não precisava de uma propriedade de compilação ou link na definição de super diretiva.
Durante o processo de compilação, o Angular puxa os valores do modelo antes de compilar, para que você possa anexar outras diretivas e o Angular cuidará disso para você.
Se essa é uma super diretiva que precisa preservar o conteúdo interno original, você pode usar
transclude : true
e substituir o interior por<ng-transclude></ng-transclude>
Espero que ajude, deixe-me saber se algo não está claro
Alex
fonte
input
tag, mas eu gostaria de fazê-lo funcionar para qualquer elemento, comodiv
s ouselect
s.element
eattrs
transferi-lo. Levou anos para resolver isso, e eu não o vi usado em nenhum lugar - mas parece funcionar bem: stackoverflow.com/a/20137542/1455709Aqui está uma solução que move as diretivas que precisam ser adicionadas dinamicamente para a exibição e também adiciona alguma lógica condicional (básica) opcional. Isso mantém a diretiva limpa, sem lógica codificada.
A diretiva pega uma matriz de objetos, cada objeto contém o nome da diretiva a ser adicionada e o valor a ser passado para ela (se houver).
Eu estava lutando para pensar em um caso de uso para uma diretiva como essa até pensar que seria útil adicionar alguma lógica condicional que apenas adiciona uma diretiva com base em alguma condição (embora a resposta abaixo ainda seja artificial). Eu adicionei uma
if
propriedade opcional que deve conter um valor, expressão ou função booleana (por exemplo, definida no seu controlador) que determina se a diretiva deve ser adicionada ou não.Também estou usando
attrs.$attr.dynamicDirectives
para obter a declaração exata de atributo usada para adicionar a diretiva (por exemplodata-dynamic-directive
,dynamic-directive
) sem os valores de string codificados para verificar.Plunker Demo
fonte
Eu queria adicionar minha solução, pois a solução aceita não funcionou para mim.
Eu precisava adicionar uma diretiva, mas também manter a minha no elemento.
Neste exemplo, estou adicionando uma diretiva de estilo ng simples ao elemento Para evitar loops de compilação infinitos e permitir que eu mantenha minha diretiva, adicionei uma verificação para ver se o que eu adicionei estava presente antes de recompilar o elemento.
fonte
Tente armazenar o estado em um atributo no próprio elemento, como
superDirectiveStatus="true"
Por exemplo:
Espero que isso ajude você.
fonte
Houve uma alteração de 1.3.x para 1.4.x.
No Angular 1.3.x, isso funcionou:
Agora no Angular 1.4.x, temos que fazer o seguinte:
(Na resposta aceita: https://stackoverflow.com/a/19228302/605586 de Khanh TO).
fonte
Uma solução simples que pode funcionar em alguns casos é criar e compilar um wrapper e anexar seu elemento original a ele.
Algo como...
Esta solução tem a vantagem de manter as coisas simples, não recompilando o elemento original.
Isso não funcionaria se alguma diretiva adicionada fosse
require
uma das diretivas do elemento original ou se o elemento original tivesse posicionamento absoluto.fonte