Link vs compilar vs controlador


529

Ao criar uma diretiva, você pode colocar o código no compilador, na função de link ou no controlador.

Nos documentos, eles explicam que:

  • função de compilação e link são usadas em diferentes fases do ciclo angular
  • controladores são compartilhados entre diretivas

No entanto, para mim não está claro, que tipo de código deve ir aonde.

Por exemplo: Posso criar funções em compilação e anexá-las ao escopo no link ou apenas anexar funções ao escopo no controlador?

Como os controladores são compartilhados entre diretivas, se cada diretiva pode ter seu próprio controlador? Os controladores são realmente compartilhados ou são apenas as propriedades do escopo?



Talvez uma visão mais abrangente das funções de diretiva: Diretivas angulares - quando usar compilação, controlador, pré-link e pós-link .
Izhaki 07/07

1
Escrevi uma postagem com um diagrama do ciclo de vida da diretiva (fase de criação). Talvez isso ajude alguém: filimanjaro.com/2014/…
average Joe

Respostas:


470

Compilar:

Essa é a fase em que o Angular realmente compila sua diretiva. Essa função de compilação é chamada apenas uma vez para cada referência à diretiva especificada. Por exemplo, digamos que você esteja usando a diretiva ng-repeat. O ng-repeat precisará procurar o elemento ao qual está anexado, extrair o fragmento html ao qual está anexado e criar uma função de modelo.

Se você usou o HandleBars, os modelos de sublinhado ou equivalente, é como compilar os modelos para extrair uma função de modelo. Para esta função de modelo, você passa dados e o valor de retorno dessa função é o html com os dados nos lugares certos.

A fase de compilação é a etapa em Angular que retorna a função de modelo. Essa função de modelo em angular é chamada de função de vinculação.

Fase de ligação:

A fase de vinculação é onde você anexa os dados ($ scope) à função de vinculação e deve retornar o html vinculado. Como a diretiva também especifica para onde esse html vai ou o que muda, já é bom ir. Essa é a função na qual você deseja fazer alterações no html vinculado, ou seja, o html que já possui os dados anexados. Em angular, se você escrever um código na função de vinculação, geralmente é a função de pós-link (por padrão). É um tipo de retorno de chamada que é chamado depois que a função de vinculação vincula os dados ao modelo.

Controlador:

O controlador é um local onde você coloca alguma lógica específica da diretiva. Essa lógica também pode entrar na função de vinculação, mas você teria que colocar essa lógica no escopo para torná-la "compartilhável". O problema disso é que você estaria corrompendo o escopo com o material das diretivas, o que não é realmente o esperado. Então, qual é a alternativa se duas diretivas querem conversar entre si / cooperar? É claro que você poderia colocar toda essa lógica em um serviço e fazer com que ambas as diretivas dependessem desse serviço, mas isso apenas traz mais uma dependência. A alternativa é fornecer um controlador para esse escopo (geralmente isolar o escopo?) E, em seguida, esse controlador é injetado em outra diretiva quando essa diretiva "requer" a outra.


67
Para esclarecer: compilar compila o modelo a ser usado em toda a página. O vinculador está vinculado a cada instância. Direita? O controlador funciona entre instâncias.
Zlatko

4
O @CMCDragonkai para cada controllerfunção de diretiva é executado após a compilação, mas antes pre-link em uma ramificação da árvore DOM local. Além disso, as funções controllere pre-linksão executadas atravessando a ramificação DOM local de maneira descendente . Depois disso, post-linké executado de maneira ascendente .
Artem Platonov

9
É apenas uma bagunça se você não entender. Há uma razão para fazer o que faz.
Demisx

3
Esta é a resposta técnica correta, no entanto, ainda tenho dúvidas sobre quando devo usar a função de link.
Nicholas Marshall

2
Devemos usar em controllervez de em linkqualquer lugar? Para que não precise alterar o código no futuro se o método precisar ser compartilhado ou se for introduzida alguma lógica? Existe alguma armadilha no uso controllero tempo todo em vez do link?
JPS

99

Queria adicionar também o que o livro O'Reily AngularJS da Equipe do Google tem a dizer:

Controlador - Crie um controlador que publique uma API para comunicação entre diretivas. Um bom exemplo é a Diretiva para Diretiva Comunicação

Link - modifique programaticamente as instâncias do elemento DOM resultantes, adicione ouvintes de eventos e configure a ligação de dados.

Compilar - Modifique programaticamente o modelo DOM para recursos nas cópias de uma diretiva, como quando usado em ng-repeat. Sua função de compilação também pode retornar funções de link para modificar as instâncias do elemento resultante.


Seu link thinkster.io não pode ser assistido sem pagar. Não é o meu link, mas talvez isso é mais adequado: toddmotto.com/directive-to-directive-communication-with-require
R. van Twisk

51

A directivepermite estender o vocabulário HTML de forma declarativa para a construção de componentes da web. O ng-appatributo é uma diretiva, assim como ng-controllere todos os ng- prefixed attributes. Directivas pode ser attributes, tagsou mesmo class names, comments.

Como nascem as diretrizes ( compilatione instantiation)

Compilar: Usaremos a compilefunção manipulateno DOM antes de ser renderizada e retornaremos uma linkfunção (que tratará do vínculo para nós). Este também é o lugar para colocar todos os métodos que precisam ser compartilhados com toda instancesessa diretiva.

link: Usaremos a linkfunção para registrar todos os ouvintes em um elemento DOM específico (clonado no modelo) e configurar nossas ligações para a página.

Se configurados na compile()função, eles seriam configurados apenas uma vez (que geralmente é o que você deseja). Se definido na link()função, ele será definido sempre que o elemento HTML for vinculado aos dados no objeto.

<div ng-repeat="i in [0,1,2]">
    <simple>
        <div>Inner content</div>
    </simple>
</div>

app.directive("simple", function(){
   return {
     restrict: "EA",
     transclude:true,
     template:"<div>{{label}}<div ng-transclude></div></div>",        
     compile: function(element, attributes){  
     return {
             pre: function(scope, element, attributes, controller, transcludeFn){

             },
             post: function(scope, element, attributes, controller, transcludeFn){

             }
         }
     },
     controller: function($scope){

     }
   };
});

CompileA função retorna a função pree postlink. Na função de pré-link, temos o modelo de instância e também o escopo do controller, mas ainda assim o modelo não está vinculado ao escopo e ainda não possui conteúdo transcluído.

PostA função de link é onde o link de postagem é a última função a ser executada. Agora o transclusionestá completo,, the template is linked to a scopee o view will update with data bound values after the next digest cycle. A linkopção é apenas um atalho para configurar uma post-linkfunção.

controlador: O controlador de diretiva pode ser passado para outra fase de vinculação / compilação de diretiva. Pode ser injetado em outras diretivas como meio de uso na comunicação entre diretivas.

Você deve especificar o nome da diretiva a ser requerida - ela deve estar vinculada ao mesmo elemento ou a seu pai. O nome pode ser prefixado com:

?  Will not raise any error if a mentioned directive does not exist.
^  Will look for the directive on parent elements, if not available on the same element.

Use colchete [‘directive1′, ‘directive2′, ‘directive3′]para exigir várias controladoras de diretivas.

var app = angular.module('app', []);

app.controller('MainCtrl', function($scope, $element) {
});

app.directive('parentDirective', function() {
  return {
    restrict: 'E',
    template: '<child-directive></child-directive>',
    controller: function($scope, $element){
      this.variable = "Hi Vinothbabu"
    }
  }
});

app.directive('childDirective', function() {
  return {
    restrict:  'E',
    template: '<h1>I am child</h1>',
    replace: true,
    require: '^parentDirective',
    link: function($scope, $element, attr, parentDirectCtrl){
      //you now have access to parentDirectCtrl.variable
    }
  }
});

1
você mencionou que mostrou como obter o parentDirectiveCtrl no controlador da criança ... neste exemplo, a criança não tem um controlador, mas sim a função de link ... Não estou preso neste problema no momento, portanto, pode não ser tão importante, mas uma pergunta curiosa.
usar o seguinte código

13

Além disso, um bom motivo para usar uma função de controlador versus link (já que ambos têm acesso ao escopo, elemento e attrs) é porque você pode passar qualquer serviço ou dependência disponível para um controlador (e em qualquer ordem), enquanto você não pode fazer isso com a função de link. Observe as diferentes assinaturas:

controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) {...

vs.

link: function(scope, element, attrs) {... //no services allowed

2
Por favor, deixe um comentário para explicar seu ponto de vista quando você votar uma resposta. Graças
svassr

53
Eu não era o downvoter, mas isto não é estritamente correto, porque você ainda pode injetar qualquer dependência necessária para a própria directiva, por exemplo: module.directive('myDirective', function($window) { etc.... Isso pode ser acessado de dentro da função de link.
Mike Chamberlain

1
este parece ser diretamente incorreto como você pode injetar serviços para a função de ligação
Código Whisperer

1
@ JoshRibakoff O resultado final é o mesmo, você tem acesso ao serviço na função de link. Não importa se é declarado nos argumentos da função ou não. A este respeito, Mike Chamberlain está correto #
Connor Wyatt

1
@ cwyatt1 Eu estava corrigindo a linguagem, o plnkr não mostra a injeção em uma função link () porque esse não é um recurso que o Angular possui. Você pode pensar que estou sendo pedante, mas o comentário dos metamatistas já descreve inúmeras diferenças importantes entre o que esse plunkr faz e o que a injeção de um controlador faz. O OP está perguntando quais são as diferenças e existem diferenças.
Josh Ribakoff

10

este é um bom exemplo para entender as fases da diretiva http://codepen.io/anon/pen/oXMdBQ?editors=101

var app = angular.module('myapp', [])

app.directive('slngStylePrelink', function() {
    return {
        scope: {
            drctvName: '@'
        },
        controller: function($scope) {
            console.log('controller for ', $scope.drctvName);
        },
        compile: function(element, attr) {
            console.log("compile for ", attr.name)
            return {
                post: function($scope, element, attr) {
                    console.log('post link for ', attr.name)
                },
                pre: function($scope, element, attr) {
                    $scope.element = element;
                    console.log('pre link for ', attr.name)
                        // from angular.js 1.4.1
                    function ngStyleWatchAction(newStyles, oldStyles) {
                        if (oldStyles && (newStyles !== oldStyles)) {
                            forEach(oldStyles, function(val, style) {
                                element.css(style, '');
                            });
                        }
                        if (newStyles) element.css(newStyles);
                    }

                    $scope.$watch(attr.slngStylePrelink, ngStyleWatchAction, true);

                    // Run immediately, because the watcher's first run is async
                    ngStyleWatchAction($scope.$eval(attr.slngStylePrelink));
                }
            };
        }
    };
});

html

<body ng-app="myapp">
    <div slng-style-prelink="{height:'500px'}" drctv-name='parent' style="border:1px solid" name="parent">
        <div slng-style-prelink="{height:'50%'}" drctv-name='child' style="border:1px solid red" name='child'>
        </div>
    </div>
</body>

4
Você poderia elaborar sobre por que este código de exemplo ajudaria a entender a diferença entre link, compilee controller?
cel sharp

você sabe como uma requirediretiva d pode ser injetada no controlador de uma diretiva dependente?
precisa saber é o seguinte

Você codificou o exemplo: Erro não capturado: [$ injector: modulerr] Falha ao instanciar o módulo myapp devido a: Erro: [$ injector: despr] Provedor desconhecido: slngStylePrelinkProvider
rofrol

7
  • compilar : usado quando precisamos modificar o modelo de diretiva, como adicionar nova expressão, anexar outra diretiva dentro desta diretiva
  • controller : usado quando precisamos compartilhar / reutilizar dados do escopo $
  • ligação : é uma função usada quando precisamos anexar manipulador de eventos ou manipular o DOM.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.