209 votes

Quelle est la différence entre la fonction compile et lien dans angularjs

Quelqu'un peut-il expliquer en termes simples ?

Les docs semble un peu obtus. Je ne reçois pas l’essence et la grande image de quand utiliser un sur l’autre. Un exemple contrastant les deux serait génial.

217voto

Mark Rajcok Points 85912
  • compiler la fonction utiliser pour le modèle de manipulation du DOM (c'est à dire, la manipulation des tElement = élément du modèle), d'où les manipulations qui s'appliquent à tous les DOM clones du modèle associé à la directive.

  • fonction link - utilisation pour l'enregistrement de DOM auditeurs (c'est à dire, $watch expressions sur l'instance portée) ainsi que l' exemple de manipulation du DOM (c'est à dire, la manipulation de iElement = instance de chaque élément).
    Il est exécuté après le modèle a été cloné. E. g., à l'intérieur d'un <li ng-repeat...>, la fonction de lien est exécuté après le <li> modèle (tElement) a été cloné dans une iElement) pour l'élément <li>.
    $Watch() permet à une directive pour être informé de l'instance de la portée des modifications de la propriété (une instance portée est associé à chaque instance), ce qui permet à la directive de rendre une instance mise à jour de la valeur pour les DOM-par copier le contenu de l'instance portée dans les DOM.

Notez que DOM transformations qui peut être fait dans la compilation de la fonction et/ou la fonction de lien.

La plupart des directives seulement besoin d'une fonction de lien, puisque la plupart des directives ne traitent qu'avec un élément du DOM (et son champ d'application).

Une façon d'aider à déterminer lequel utiliser: considérer que la compilation de la fonction ne reçoit pas un scope argument. (Je suis volontairement ignorant la transclude fonction de liaison de l'argument, qui reçoit un transcluded portée -- c'est rarement utilisée.) Donc la compilation de la fonction ne peut pas faire tout ce que vous voulez faire qui nécessite un exemple) champ d'application -- vous ne pouvez pas $regarder n'importe quel modèle/exemple propriétés de l'étendue, vous ne pouvez pas manipuler le DOM à l'aide de l'instance de la portée de l'information, vous ne pouvez pas appeler des fonctions définies sur l'instance de la portée, etc.

Cependant, la compilation de la fonction (comme la fonction de lien) n'ont accès aux attributs. Donc, si vos manipulations DOM ne nécessitent pas l'exemple de la portée, vous pouvez utiliser la compilation de la fonction. Voici un exemple d'une directive qui n'utilise qu'une compilation de la fonction, pour ces raisons. Il examine les attributs, mais il n'a pas besoin d'une instance portée pour faire son travail.

Voici un exemple d'une directive qui n'utilise que de la compilation de la fonction. La directive ne doit transformer le modèle DOM, donc une compilation de la fonction peut être utilisée.

Une autre façon de vous aider à déterminer lequel utiliser: si vous n'utilisez pas le "élément" paramètre dans la fonction de lien, alors vous n'avez probablement pas besoin d'une fonction de lien.

Puisque la plupart des directives ont une fonction de lien, je ne vais pas fournir des exemples -- il devrait être très facile à trouver.

Notez que si vous avez besoin d'une compilation de la fonction et une fonction de lien (ou pré-et post-fonctions de liaison), la compilation de la fonction doit retourner la fonction de lien(s) parce que le "lien" de l'attribut est ignoré si le 'compiler' attribut n'est pas défini.

Voir aussi la Différence entre le "contrôleur" et "lien" fonctions lors de la définition d'un angular.js la directive

68voto

Tony K. Points 2537

J'ai battu ma tête contre le mur sur cela pour un couple de jours, et je pense qu'un peu plus d'explication est dans l'ordre.

Fondamentalement, les docs mentionner que la séparation est en grande partie l'amélioration de la performance. Je voudrais rappeler que la phase de compilation est principalement utilisé lorsque vous avez besoin de modifier le DOM, AVANT la sous-éléments eux-mêmes sont compilés.

Pour nos fins, je vais insister sur la terminologie, ce qui est contraire à confusion:

Le compilateur de SERVICE ($compiler) est l'angle de mécanisme qui traite les DOM et exécute les différents morceaux de code dans les directives.

La compilation de la FONCTION est un peu de code à l'intérieur d'une directive, ce qui est exécutée à un moment donné PAR le compilateur ($compiler).

Quelques notes à propos de la compilation de la FONCTION:

  1. Vous ne pouvez pas modifier l'élément RACINE (celui de votre directive affecte), puisqu'il est déjà compilé à partir de l'extérieur au niveau de DOM (le compiler SERVICE a déjà scanné pour les directives sur cet élément).

  2. Si vous souhaitez ajouter d'autres directives (imbriqué) éléments, vous pouvez soit:

    1. Ont pour les ajouter au cours de la phase de compilation.

    2. Ont pour injecter de la compilation de service dans le lien entre la phase et de compiler les éléments manuellement. MAIS, méfiez-vous de compiler deux fois la même chose!

Il est également utile de voir comment la nidification et des appels explicites à $compiler travail, j'ai donc créé une aire de jeux pour affichage à http://jsbin.com/imUPAMoV/1/edit. Fondamentalement, il enregistre tout les étapes de la console.journal.

Je vais indiquer les résultats de ce que vous souhaitez voir dans cette corbeille. Pour un DOM de la coutume directives tp et sp imbriqués comme suit:

<tp>
   <sp>
   </sp>
</tp>

Angulaire compiler SERVICE composez le:

tp compile
sp compile
tp pre-link
sp pre-link
sp post-link
tp post-link

Le jsbin code a aussi le tp post-lien de la FONCTION appeler explicitement la compilation de SERVICE sur un troisième directive (vers le haut), ce qui ne les trois étapes à la fin.

Maintenant, je veux marcher à travers un couple de scénarios de montrer comment l'on peut aller sur l'aide de la compiler et lier de faire différentes choses:

SCÉNARIO 1: la Directive comme une MACRO

Vous souhaitez ajouter une directive (dire ng-show) de manière dynamique à quelque chose dans votre modèle que vous pouvez tirer d'un attribut.

Disons que vous avez un templateUrl qui pointe vers:

<div><span><input type="text"></span><div>

et vous voulez une coutume directive:

<my-field model="state" name="address"></my-field>

qui transforme les DOM en ceci:

<div><span ng-show="state.visible.address"><input ng-model="state.fields.address" ...>

fondamentalement, vous voulez réduire réutilisable par avoir un modèle cohérent de la structure de votre directive peut interpréter. En d'autres termes: vous voulez une macro.

C'est d'une grande utilité pour la phase de compilation, puisque vous pouvez la base de toutes les manipulations DOM sur des choses que vous savez juste dans les attributs. Simplement utiliser jQuery pour ajouter les attributs:

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() {}
   };
}

La séquence des opérations sera (vous pouvez le voir via le jsbin mentionné plus haut):

  1. La compilation de SERVICE trouve mon champ
  2. Il appelle la compilation de la FONCTION sur la directive, qui met à jour les DOM.
  3. La compilation puis, le SERVICE des promenades dans la DOM, et COMPILE (de manière récursive)
  4. La compilation puis, le SERVICE d'appels pré-lien de haut en bas
  5. La compilation de SERVICE, puis appelle la post-lien de BAS en HAUT, donc, mon-domaine de liaison de la fonction est appelée APRÈS nœuds intérieurs ont été liés.

Dans l'exemple ci-dessus, aucune liaison n'est nécessaire, puisque la totalité de la directive du travail a été fait dans la compilation de la FONCTION.

À tout moment, le code dans une directive peut demander au compilateur de SERVICE à exécution sur des éléments supplémentaires.

Cela signifie que nous pouvons faire exactement la même chose dans une fonction de lien si vous injectez de la compilation de service:

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);
    }
});

Si vous êtes sûr que les éléments que vous êtes de passage à $compiler SERVICE ont été à l'origine de la directive (par exemple, ils sont venus à partir d'un modèle que vous avez défini, ou que vous venez de créer avec angulaire.element()), puis le résultat final est à peu près la même qu'avant (bien que vous pouvez peut-être la répétition d'une partie du travail). Toutefois, si l'élément a d'autres directives sur elle, vous venez de ceux causés à être traitées de nouveau, ce qui peut causer toutes sortes de comportement erratique (par exemple, le double enregistrement des événements et des montres).

Ainsi, la phase de compilation est un bien meilleur choix pour la macro-style de travail.

SCÉNARIO 2: DOM configuration via le champ de données

C'est celui qui suit à partir de l'exemple ci-dessus. Supposons que vous avez besoin d'accéder à la portée tout en manipulant le DOM. Eh bien, dans ce cas, la compilation section est inutile de vous, comme il arrive devant un champ d'application est disponible.

Donc, disons que vous voulez pour renflouer une entrée avec des validations, mais que vous souhaitez exporter vos validations à partir d'un serveur-côté ORM classe (SEC), et d'auto-appliquer et de générer le bon côté client de l'INTERFACE utilisateur pour ces validations.

Votre modèle peut pousser:

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'
};

et vous pourriez souhaiter une directive:

<form name="theForm">
  <my-field model="state" metadata="metadata" name="address">
</form>

auto-inclure les directives appropriées et les divs pour montrer les diverses erreurs de validation:

<form name="theForm">
  <div>
    <input ng-model="state.address" type="text">
    <div ng-show="theForm.address.$error.pattern">Address must begin with a number</input>
...

Dans ce cas, vous avez certainement besoin d'avoir accès au champ d'application (puisque c'est l'endroit où vos validations sont stockées), et vont avoir à compiler les ajouts manuellement, en faisant attention de ne pas double-compiler les choses. (comme une note de côté, vous devez définir un nom sur le contenant de la balise form (je suis en supposant que theForm ici), et pouvaient y accéder en lien avec iElement.parent().contrôleur('form').$nom).

Dans ce cas, il n'y a pas de point dans l'écriture de la compilation de la fonction. Le lien est vraiment ce que vous voulez. Les étapes seraient:

  1. De définir un modèle qui est totalement dénué de angulaire directives.
  2. Définir une fonction de lien qui ajoute les divers attributs
  3. SUPPRIMER tout angulaire directives que vous pouvez laisser sur votre élément de niveau supérieur (le mon champ de la directive). Ils ont déjà été traités, c'est une façon de les garder à partir de la double-traitées.
  4. Terminer par un appel à la compilation d'un SERVICE sur votre élément de niveau supérieur

Comme suit:

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
    }
  };
});

Vous pouvez, bien sûr, de compiler les éléments imbriqués l'un par un pour éviter d'avoir à vous soucier de la double traitement de ng directives lors de la compilation de l'élément de niveau supérieur de nouveau.

Une dernière remarque sur ce scénario: je implicite vous seriez en poussant la définition des validations à partir d'un serveur, et dans mon exemple, j'ai montré que les données déjà dans le champ d'application. Je laisse comme exercice pour le lecteur de comprendre comment on peut traiter avec avoir besoin d'extraire des données à partir d'une API REST (indice: différé de la compilation).

SCÉNARIO 3: les deux sens de la liaison de données via le lien

Bien sûr, l'utilisation la plus courante de lien, il suffit de raccorder les deux sens de la liaison de données via watch/appliquer. La plupart des directives entrent dans cette catégorie, alors qu'il est suffisamment couverts par ailleurs.

50voto

Matt Ball Points 165937

À partir de la documentation:

Compilateur

Compilateur angulaire de service qui traverse les DOM à la recherche pour les attributs. Le processus de compilation se produit en deux phases.

  1. Compiler: parcourir le DOM et de recueillir toutes les directives. Le résultat est une fonction de liaison.

  2. Lien: combiner les directives de la portée et de produire une vue en direct. Tout changement dans le champ d'application du modèle sont reflétées dans la vue, et toutes les interactions de l'utilisateur avec le point de vue sont reflétées dans le champ d'application du modèle. Rendre le champ d'application du modèle à une seule source de vérité.

Certaines directives telles ng-repeat clone éléments DOM, une fois pour chaque élément dans la collection. Avoir de la compilation et de la phase de liaison améliore les performances depuis le cloné modèle ne doit être compilé en une fois, et ensuite lié une fois pour chaque clone instance.

Ainsi, au moins dans certains cas, les deux phases existent séparément comme une optimisation.


@UmurKontacı:

Si vous allez faire de DOM transformations, il convient compile. Si vous voulez ajouter quelques fonctionnalités qui sont des changements de comportement, il faut en link.

18voto

SunnyShah Points 4088

C'est à partir de Misko s 'parler sur les directives. http://youtu.be/WqmeI5fZcho?t=16m23s

Pensez à le compilateur fonction la chose qui fonctionne sur un modèle et la chose qui est autorisé à changer le modèle lui-même, par exemple, l'ajout d'une classe ou d' quelque chose comme ça. Mais c'est la fonction de liaison qui ne fait le travail de liaison, les deux ensemble, parce que la fonction de liaison a l'accès à la portée et la fonction de liaison qui s'exécute une fois pour chaque instanciation du modèle particulier. Si le seul type de choses que vous pouvez placer à l'intérieur de la compiler les fonctions sont des choses que sont communs à l'ensemble de toutes les instances.

6voto

pixelbits Points 5710

Deux Phases: Compiler et Lier

Compiler:

Parcourir l'arborescence du DOM à la recherche de directives (éléments / attributs / classes / commentaires). Chaque compilation d'une directive peut modifier son modèle, ou modifier son contenu, qui n'a pas été compilé encore. Une fois qu'une directive est inégalable, elle renvoie une fonction de liaison, qui est utilisé dans une phase ultérieure de lier les éléments entre eux. À la fin de la phase de compilation, nous avons compilé une liste de directives et de leurs correspondants reliant fonctions.

Lien:

Lorsqu'un élément est lié, l'arbre du DOM est cassé à son point de branchement dans l'arborescence DOM, et le contenu sont remplacés par les compilée (et lien) instance du modèle. L'original déplacées contenu est soit rejetée, ou dans le cas de la transclusion, re-liés de nouveau dans le modèle. Avec transclusion, les deux pièces sont liées ensemble (un peu comme une chaîne, avec le modèle de pièce dans le milieu). Lorsque la fonction de lien est appelé, le modèle a déjà été lié à un champ, et ajouté en tant qu'enfant de l'élément. La fonction de lien est pour vous l'occasion de manipuler le DOM plus loin et de configuration de changement d'auditeurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X