JS angular: Qual é a necessidade da função de link da diretiva quando já tínhamos o controlador da diretiva com escopo?

199

Preciso executar algumas operações no escopo e no modelo. Parece que eu posso fazer isso na linkfunção ou na controllerfunção (já que ambos têm acesso ao escopo).

Quando é que eu tenho que usar a linkfunção e não o controlador?

angular.module('myApp').directive('abc', function($timeout) {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: true,
        link: function(scope, elem, attr) { /* link function */ },
        controller: function($scope, $element) { /* controller function */ }
    };
}

Além disso, eu entendo que linké o mundo não angular. Então, eu posso usar $watch, $digeste $apply.

Qual é o significado da linkfunção, quando já tínhamos controlador?

Yugal Jindle
fonte
9
O que você quer dizer com " Além disso, eu entendo que ligação é o mundo não-angular. Então, eu posso usar $watch, $digeste $apply. "?
Novamente
2
No interior link, não vemos nenhuma mágica angular. ou seja, sem ligações bidirecionais, etc. Só que temos a API do angular disponível para uso.
Yugal Jindle

Respostas:

299

Depois da minha primeira luta com o linke controllerfunções e ler muito sobre eles, acho que agora eu tenho a resposta.

Primeiro vamos entender ,

Como as diretivas angulares funcionam em poucas palavras:

  • Começamos com um modelo (como uma string ou carregado em uma string)

    var templateString = '<div my-directive>{{5 + 10}}</div>';

  • Agora, isso templateStringé envolvido como um elemento angular

    var el = angular.element(templateString);

  • Com el, agora compilamos $compilepara recuperar a função de link .

    var l = $compile(el)

    Aqui está o que acontece,

    • $compile percorre todo o modelo e coleta todas as diretivas que ele reconhece.
    • Todas as diretivas descobertas são compiladas recursivamente e suas linkfunções são coletadas.
    • Em seguida, todas as linkfunções são agrupadas em uma nova linkfunção e retornadas como l.
  • Finalmente, fornecemos scopefunção para essa função l(link) que executa ainda mais as funções de link agrupadas com esse scopee seus elementos correspondentes.

    l(scope)

  • Isso adiciona o templatecomo um novo nó ao DOMe chama, controlleradicionando seus relógios ao escopo que é compartilhado com o modelo no DOM.

insira a descrição da imagem aqui

Comparando compilação vs link x controlador :

  • Toda diretiva é compilada apenas uma vez e a função de link é mantida para reutilização. Portanto, se houver algo aplicável a todas as instâncias de uma diretiva, ele deverá ser executado dentro da compilefunção da diretiva .

  • Agora, após a compilação, temos a linkfunção que é executada ao anexar o modelo ao DOM . Portanto, executamos tudo o que é específico a cada instância da diretiva. Por exemplo: anexando eventos , alterando o modelo com base no escopo , etc.

  • Finalmente, o controlador deve estar disponível para ser ativo e reativo enquanto a diretiva trabalha no DOM(depois de se conectar). Portanto:

    (1) Após configurar a visualização [ V ] (isto é, modelo) com o link. $scopeé nosso [ M ] e $controlleré nosso [ C ] no MVC

    (2) Aproveite a ligação bidirecional com $ scope , configurando relógios.

    (3) $scopeespera-se que os relógios sejam adicionados ao controlador, pois é isso que está observando o modelo durante o tempo de execução.

    (4) Finalmente, controllertambém é usado para poder se comunicar entre diretivas relacionadas. (Como myTabsexemplo em https://docs.angularjs.org/guide/directive )

    (5) É verdade que também poderíamos ter feito tudo isso na linkfunção, mas é sobre a separação de preocupações .

Portanto, finalmente, temos o seguinte que se encaixa perfeitamente em todas as peças:

insira a descrição da imagem aqui

Yugal Jindle
fonte
5
Eu também achei este artigo útil para a compreensão da ordem de execução aqui: O âmago da questão das funções de compilação e link dentro directivas AngularJS
BobbyA
4
Ótima explicação. Gostaria de mencionar que o controlador é chamado antes da função de link.
Jsbisht
38
controlador é executado antes do link
Royi Namir 18/12/2015
10
Enfurece-me que o Stack Overflow exija que as edições tenham no mínimo 6 caracteres, não permitindo, portanto, que eu corrija a ortografia de vamos nesta resposta.
usar o seguinte comando
79

Por que os controladores são necessários

A diferença entre linke controllerentra em jogo quando você deseja aninhar diretivas no seu DOM e expor as funções da API da diretiva pai para as aninhadas.

Dos documentos :

Prática recomendada: use o controlador quando desejar expor uma API a outras diretivas. Caso contrário, use o link.

Digamos que você queira ter duas diretivas my-forme my-text-inputque a my-text-inputdiretiva apareça apenas dentro my-forme em nenhum outro lugar.

Nesse caso, você vai dizer ao definir a diretiva my-text-inputque requer um controlador do parentelemento DOM usando o argumento requer, como este: require: '^myForm'. Agora, o controlador do elemento pai entrará injectedna linkfunção como o quarto argumento a seguir $scope, element, attributes. Você pode chamar funções nesse controlador e se comunicar com a diretiva pai.

Além disso, se esse controlador não for encontrado, um erro será gerado.

Por que usar o link

Não há necessidade real de usar a linkfunção se alguém estiver definindo o, controllerpois o $scopeestá disponível no controller. Além disso, ao definir ambos linke controller, é preciso ter cuidado com a ordem de invocação dos dois ( controlleré executada antes).

No entanto, de acordo com a maneira Angular , a maioria das manipulações DOM e ligações bidirecionais $watchersgeralmente é feita na linkfunção, enquanto a API para filhos e $scopemanipulação é feita na controller. Esta não é uma regra rígida e rápida, mas isso tornará o código mais modular e ajudará na separação de preocupações (o controlador manterá o directiveestado e a linkfunção manterá as DOMligações + externas).

musically_ut
fonte
Isso é ótimo. Agora, você pode me ajudar com a segunda parte da pergunta?
Yugal Jindle
Quero dizer, já que tínhamos o controlador que poderia ter sido usado para se comunicar com outras diretivas. Então, qual era a necessidade link?
Yugal Jindle
1
Sua resposta de alguma forma não responde à pergunta real.
Yugal Jindle
1
Existem problemas que ocorrem quando definimos um controller? Por que vou querer inventar uma função totalmente nova apenas para evitar a definição de controlador?
Yugal Jindle
1
parece que @scalaGirl s da ligação não está mais funcionando
Minato
17

A controllerfunção / objeto representa um MVC (Model-View-Controller) da abstração. Embora não haja nada novo para escrever sobre o MVC, ainda é a vantagem mais significativa do angular: divida as preocupações em pedaços menores. E é isso, nada mais, por isso, se você precisa para reagir a Modelmudanças provenientes de Viewo Controlleré o direito pessoa para fazer esse trabalho.

A história sobre a linkfunção é diferente, vem de uma perspectiva diferente da MVC. E é realmente essencial, uma vez que queremos cruzar os limites de um controller/model/view (modelo) .

Vamos começar com os parâmetros que são passados ​​para a linkfunção:

function link(scope, element, attrs) {
  • scope é um objeto Angular scope.
  • O elemento é o elemento embrulhado em jqLite que esta diretiva corresponde.
  • attrs é um objeto com os nomes de atributos normalizados e seus valores correspondentes.

Para colocar o linkcontexto, devemos mencionar que todas as diretivas estão passando por essas etapas do processo de inicialização: Compilar , Vincular . Um extrato do livro de Brad Green e Shyam Seshadri Angular JS :

Fase de compilação (uma irmã do link, vamos mencionar aqui para obter uma imagem clara):

Nesta fase, o Angular percorre o DOM para identificar todas as diretivas registradas no modelo. Para cada diretiva, ele transforma o DOM com base nas regras da diretiva (modelo, substitui, transclui e assim por diante) e chama a função de compilação, se existir. O resultado é uma função de modelo compilada,

Fase de ligação :

Para tornar a visualização dinâmica, o Angular executa uma função de link para cada diretiva. As funções de link normalmente criam ouvintes no DOM ou no modelo. Esses ouvintes mantêm a visualização e o modelo sincronizados o tempo todo.

Um bom exemplo de como usar o linkpode ser encontrado aqui: Criando diretivas personalizadas . Veja o exemplo: Criando uma diretiva que manipula o DOM , que insere uma "data e hora" na página, atualizada a cada segundo.

Apenas um pequeno trecho dessa fonte rica acima, mostrando a verdadeira manipulação com o DOM. Há uma função conectada ao serviço $ timeout e também é limpa em sua chamada de destruidor para evitar vazamentos de memória

.directive('myCurrentTime', function($timeout, dateFilter) {

 function link(scope, element, attrs) {

 ...

 // the not MVC job must be done
 function updateTime() {
   element.text(dateFilter(new Date(), format)); // here we are manipulating the DOM
 }

 function scheduleUpdate() {
   // save the timeoutId for canceling
   timeoutId = $timeout(function() {
     updateTime(); // update DOM
     scheduleUpdate(); // schedule the next update
   }, 1000);
 }

 element.on('$destroy', function() {
   $timeout.cancel(timeoutId);
 });

 ...
Radim Köhler
fonte
3
Você parece ter comparado compilere link. Eles questão está pedindo por isso que linkquando já tínhamoscontroller
Yugal Jindle
Estendi a resposta para descrever até o controlador em mais detalhes. Agora os conceitos do controllervs linkdevem ser mais claros ...
Radim Köhler
1
Eu posso procurar me contentar com essa explicação. Mas parece ser meio embaçado lá. Seria ótimo se alguém da equipe angular pudesse falar por isso, projetando para onde eles a veem - para o linkou para o controller.
Yugal Jindle
1
Essa é a única parte que eu quero entender (quando não é suficiente?). Além disso, recebo todos os benefícios do angular controllere linké relativamente feio. Portanto, a equipe angular deve ter uma boa razão para isso, em vez de apenas uma opção.
Yugal Jindle
1
Pergunta: Quando o controlador não é suficiente? Resp: Quando você precisar de uma experiência fora do Angular, como usar um plug-in JQuery ou usar o recurso JQlite, conforme mencionado no documento ( docs.angularjs.org/api/ng/function/angular.element:) , será necessário link
Hasteq 20/08/2015