Alguém pode explicar em termos simples?
Os documentos parecem um pouco obtusos. Eu não estou recebendo a essência e a grande figura de quando usar um sobre o outro. Um exemplo que contrasta os dois seria fantástico.
function de compilation – use para manipulação de DOM de modelo (ou seja, manipulação de elemento tElement = template), portanto, manipulações que se aplicam a todos os clones DOM do modelo associado à diretiva.
function de link – use para registrar ouvintes DOM (isto é, expressões $ watch no escopo de instância) bem como manipulação de DOM de instância (ou seja, manipulação de elemento de instância individual iElement).
É executado depois que o modelo foi clonado. Por exemplo, dentro de uma
Observe que as transformações DOM podem ser feitas na function de compilation e / ou na function de link.
A maioria das diretivas só precisa de uma function de link, já que a maioria das diretivas trata apenas de uma instância de elemento DOM específica (e seu escopo de instância).
Uma maneira de ajudar a determinar qual usar: considere que a function de compilation não recebe um argumento de scope
. (Estou propositalmente ignorando o argumento de function de vinculação de transclude, que recebe um escopo transcluído – isso raramente é usado.) Portanto, a function de compilation não pode fazer nada que você queira fazer que exija um escopo (instância) – você pode Observe todas as propriedades de escopo de modelo / instância, você não pode manipular o DOM usando informações de escopo de instância, você não pode chamar funções definidas no escopo da instância, etc.
No entanto, a function de compilation (como a function de link) tem access aos atributos. Portanto, se as manipulações do DOM não exigirem o escopo da instância, você poderá usar uma function de compilation. Aqui está um exemplo de uma diretiva que usa apenas uma function de compilation, por esses motivos. Ele examina os atributos, mas não precisa de um escopo de instância para fazer seu trabalho.
Aqui está um exemplo de uma diretiva que também usa apenas uma function de compilation. A diretiva só precisa transformar o modelo DOM, portanto, uma function de compilation pode ser usada.
Outra maneira de ajudar a determinar qual usar: se você não usar o parâmetro “element” na function de link, provavelmente não precisará de uma function de link.
Como a maioria das diretivas tem uma function de link, não fornecerei exemplos – elas devem ser muito fáceis de encontrar.
Observe que, se você precisar de uma function de compilation e de link (ou funções de link de pré e pós), a function de compilation deve retornar as funções de link porque o atributo ‘link’ é ignorado se o atributo ‘compile’ estiver definido.
Veja também
Eu bati minha cabeça contra a parede por alguns dias, e sinto que um pouco mais de explicação está em ordem.
Basicamente, os documentos mencionam que a separação é em grande parte um aprimoramento de desempenho. Gostaria de reiterar que a fase de compilation é usada principalmente quando você precisa modificar o DOM ANTES que os subelementos sejam compilados.
Para nossos propósitos, vou enfatizar a terminologia, que é confusa:
O compilador SERVICE ($ compile) é o mecanismo angular que processa o DOM e executa os vários bits de código nas diretivas.
A compilation FUNCTION é um bit de código dentro de uma diretiva, que é executada em um determinado momento pelo compilador SERVICE ($ compile).
Algumas notas sobre a function compilar:
Você não pode modificar o elemento ROOT (aquele que sua diretiva afeta), já que ele já está sendo compilado a partir do nível externo do DOM (a compilation SERVICE já varreu as diretivas daquele elemento).
Se você quiser adicionar outras diretivas a elementos (nesteds), você:
Tem que adicioná-los durante a fase de compilation.
Tem que injetar o serviço de compilation na fase de vinculação e compilar os elementos manualmente. MAS, cuidado com a compilation de algo duas vezes!
Também é útil ver como o aninhamento e as chamadas explícitas para $ compile funcionam, então criei um playground para visualizá-lo em http://jsbin.com/imUPAMoV/1/edit . Basicamente, ele apenas registra as etapas no console.log.
Eu declararei os resultados do que você veria naquela checkbox aqui. Para um DOM de diretivas personalizadas tp e sp aninhadas da seguinte forma:
Compile Angular SERVICE chamará:
tp compile sp compile tp pre-link sp pre-link sp post-link tp post-link
O código jsbin também tem a function tp post-link explicitamente chamada de compile SERVICE em uma terceira diretiva (up), que faz todas as três etapas no final.
Agora, quero percorrer alguns cenários para mostrar como é possível usar a compilation e o link para fazer várias coisas:
CENÁRIO 1: Directiva como MACRO
Você deseja adicionar uma diretiva (digamos ng-show) dinamicamente a algo em seu modelo que possa derivar de um atributo.
Digamos que você tenha um templateUrl que aponte para:
e você quer uma diretiva personalizada:
que transforma o DOM nisso:
Basicamente, você quer reduzir o clichê com alguma estrutura de modelo consistente que sua diretiva possa interpretar. Em outras palavras: você quer uma macro.
Este é um ótimo uso para a fase de compilation, já que você pode basear todas as manipulações do DOM em coisas que você conhece apenas dos atributos. Basta usar o jQuery para adicionar os atributos:
compile: function(tele, tattr) { var span = jQuery(tele).find('span').first(); span.attr('ng-show', tattr.model + ".visible." + tattr.name); ... return { pre: function() { }, post: function() {} }; }
A seqüência de operações será (você pode ver isso através do jsbin mencionado anteriormente):
No exemplo acima, nenhuma vinculação é necessária, uma vez que todo o trabalho da diretiva foi feito na function compilar.
A qualquer momento, o código em uma diretiva pode solicitar que o compilador SERVICE seja executado em elementos adicionais.
Isso significa que podemos fazer exatamente a mesma coisa em uma function de link se você injetar o serviço de compilation:
directive('d', function($compile) { return { // REMEMBER, link is called AFTER nested elements have been compiled and linked! link: function(scope, iele, iattr) { var span = jQuery(iele).find('span').first(); span.attr('ng-show', iattr.model + ".visible." + iattr.name); // CAREFUL! If span had directives on it before // you will cause them to be processed again: $compile(span)(scope); } });
Se você tem certeza de que os elementos que você está passando para $ compile SERVICE originalmente eram livres de diretivas (por exemplo, eles vieram de um template que você definiu ou você os criou com angular.element ()), então o resultado final é praticamente o mesmo que antes (embora você possa estar repetindo algum trabalho). No entanto, se o elemento tiver outras diretivas, você fará com que elas sejam processadas novamente, o que pode causar todos os tipos de comportamento errático (por exemplo, registro duplo de events e relógios).
Assim, a fase de compilation é uma escolha muito melhor para o trabalho de estilo macro.
CENÁRIO 2: Configuração do DOM por meio de dados de escopo
Este segue do exemplo acima. Suponha que você precise de access ao escopo durante a manipulação do DOM. Bem, nesse caso, a seção de compilation é inútil para você, já que isso acontece antes que um escopo esteja disponível.
Portanto, digamos que você queira extrair uma input com validações, mas deseja exportar suas validações de uma class ORM do lado do servidor (DRY) e fazer com que elas se apliquem automaticamente e gerem a UI do lado do cliente adequada para essas validações.
Seu modelo pode empurrar:
scope.metadata = { validations: { address: [ { pattern: '^[0-9]', message: "Address must begin with a number" }, { maxlength: 100, message: "Address too long" } ] } }; scope.state = { address: '123 Fern Dr' };
e você pode querer uma diretiva:
para include automaticamente as diretivas e divs corretas para mostrar os vários erros de validação:
Nesse caso, você definitivamente precisa acessar o escopo (já que é onde suas validações são armazenadas), e terá que compilar as adições manualmente, novamente tomando cuidado para não duplicar as coisas. (como uma nota lateral, você precisaria definir um nome na tag de formulário contendo (estou assumindo oForm aqui), e poderia acessá-lo em um link com iElement.parent (). controller (‘form’). $ name) .
Neste caso, não há sentido em escrever uma function de compilation. Link é realmente o que você quer. Os passos seriam:
Igual a:
angular.module('app', []). directive('my-field', function($compile) { return { link: function(scope, iele, iattr) { // jquery additions via attr() // remove ng attr from top-level iele (to avoid duplicate processing) $compile(iele)(scope); // will pick up additions } }; });
Você poderia, é claro, compilar os elementos nesteds um a um para evitar ter que se preocupar com o processamento duplicado de diretivas ng ao compilar o elemento de nível superior novamente.
Uma nota final sobre este cenário: Eu sugeri que você estaria empurrando a definição das validações de um servidor e, no meu exemplo, mostrei-as como dados já no escopo. Deixo como um exercício para o leitor descobrir como alguém pode lidar com a necessidade de extrair esses dados de uma API REST (dica: compilation adiada).
CENÁRIO 3: vinculação de dados bidirecional via link
É claro que o uso mais comum do link é simplesmente conectar a binding de dados bidirecional via watch / apply. A maioria das diretivas se enquadra nessa categoria, portanto, é adequadamente abordada em outros lugares.
Dos docs:
Compilador
Compiler é um serviço angular que percorre o DOM procurando por atributos. O processo de compilation acontece em duas fases.
Compile: percorra o DOM e colete todas as diretivas. O resultado é uma function de vinculação.
Link: combine as diretivas com um escopo e produza uma exibição ao vivo. Quaisquer alterações no modelo de escopo são refletidas na exibição e qualquer interação do usuário com a exibição é refletida no modelo de escopo. Tornar o modelo de escopo uma única fonte de verdade.
Algumas diretivas como
ng-repeat
clonam elementos DOM uma vez para cada item na coleção. Ter uma fase de compilation e link melhora o desempenho, pois o modelo clonado só precisa ser compilado uma vez e, em seguida, vinculado uma vez para cada instância de clone.
Então, pelo menos em alguns casos, as duas fases existem separadamente como uma otimização.
De @ UmurKontacı :
Se você vai fazer transformações DOM, deve ser
compile
. Se você quiser adicionar alguns resources que são mudanças de comportamento, ele deve estar nolink
.
Isto é da palestra de Misko sobre diretivas. http://youtu.be/WqmeI5fZcho?t=16m23s
Pense na function de compilador como a coisa que funciona em um modelo e a coisa que tem permissão para alterar o próprio modelo, por exemplo, adicionando uma class a ele ou algo do tipo. Mas é a function de vinculação que realmente faz o trabalho de vincular os dois juntos porque a function de vinculação tem access ao escopo e é a function de vinculação que é executada uma vez para cada instanciação do modelo específico. Portanto, o único tipo de coisas que você pode colocar dentro das funções de compilation são coisas comuns em todas as instâncias.
Pouco atrasado para o fio. Mas, para o benefício dos futuros leitores:
Eu me deparei com o seguinte vídeo que explica Compile e Link em Angular JS de uma forma muito boa:
https://www.youtube.com/watch?v=bjFqSyddCeA
Não seria agradável copiar / digitar todo o conteúdo aqui. Eu tirei algumas capturas de canvas do vídeo, o que explica cada estágio das fases Compile e Link:
A segunda canvas é um pouco confusa. Mas, se seguirmos a numeração dos passos, é bastante simples.
Primeiro ciclo: “Compile” é executado em todas as diretivas primeiro.
Segundo ciclo: “Controlador” e “Pre-Link” são executados (apenas um após o outro) Terceiro ciclo: “Post-Link” é executado na ordem inversa (começando do mais interno)
A seguir está o código, que demonstra o acima:
var app = angular.module ('app', []); app.controller ('msg', ['$ scope', function ($ scope) { }]); app.directive ('message', function ($ interpolate) { Retorna{ compile: function (tElement, tAttributes) { console.log (tAttributes.text + "- em compilation .."); Retorna { pre: function (scope, iElement, iAttributes, controller) { console.log (iAttributes.text + "-In pre .."); } post: function (scope, iElement, iAttributes, controller) { console.log (iAttributes.text + "-In Post .."); } } } controller: function ($ scope, $ elemento, $ attrs) { console.log ($ attrs.text + "-In controller .."); } } });
ATUALIZAR:
A parte 2 do mesmo vídeo está disponível aqui: https://www.youtube.com/watch?v=1M3LZ1cu7rw O vídeo explica mais sobre como modificar o DOM e lidar com events durante o processo Compile e Link do Angular JS, em um exemplo simples .
Duas fases: compilar e vincular
Compilar:
Atravessar a tree DOM procurando por diretivas (elementos / atributos / classs / comentários). Cada compilation de uma diretiva pode modificar seu modelo ou modificar seu conteúdo que ainda não foi compilado. Quando uma diretiva é correspondida, ela retorna uma function de vinculação, que é usada em uma fase posterior para vincular os elementos. No final da fase de compilation, temos uma lista de diretivas compiladas e suas correspondentes funções de vinculação.
Ligação:
Quando um elemento é vinculado, a tree DOM é quebrada em seu ponto de ramificação na tree DOM e o conteúdo é substituído pela instância compilada (e vinculada) do modelo. O conteúdo original deslocado é descartado ou, no caso de transclusão, é novamente ligado ao modelo. Com a transclusão, as duas partes são ligadas juntas (como uma corrente, com a peça do modelo no meio). Quando a function de binding é chamada, o modelo já foi vinculado a um escopo e adicionado como filho do elemento. A function de link é a sua oportunidade de manipular o DOM e configurar ouvintes de mudança.
Esta questão é antiga, gostaria de fazer um pequeno resumo que pode ajudar: