Angular JS: Quel est le besoin de la fonction de liaison de la directive alors que nous avions déjà un contrôleur de directive avec portée?

199

J'ai besoin d'effectuer certaines opérations sur la portée et le modèle. Il semble que je puisse le faire dans la linkfonction ou dans la controllerfonction (car les deux ont accès à la portée).

Quand est-ce le cas lorsque je dois utiliser la linkfonction et non le contrôleur?

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 */ }
    };
}

Aussi, je comprends que linkc'est le monde non angulaire. Donc, je peux utiliser $watch, $digestet $apply.

Quelle est la signification de la linkfonction, alors que nous avions déjà un contrôleur?

Yugal Jindle
la source
9
Que voulez-vous dire par " Aussi, je comprends que le lien est le monde non angulaire. Donc, je peux utiliser $watch, $digestet $apply. "?
musically_ut
2
A l'intérieur, linknous ne voyons aucune magie angulaire. c'est-à-dire pas de liaisons à 2 voies, etc. Juste que nous avons l'api de l'angulaire disponible.
Yugal Jindle

Réponses:

299

Après ma première lutte avec les linket controllerfonctions et en lisant beaucoup de choses sur eux, je pense que maintenant j'ai la réponse.

Tout d' abord permet de comprendre ,

Comment fonctionnent les directives angulaires en bref:

  • Nous commençons par un modèle (sous forme de chaîne ou chargé dans une chaîne)

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

  • Maintenant, templateStringc'est enveloppé comme un élément angulaire

    var el = angular.element(templateString);

  • Avec el, maintenant nous le compilons avec $compilepour récupérer la fonction de lien .

    var l = $compile(el)

    Voici ce qui se passe,

    • $compile parcourt tout le modèle et recueille toutes les directives qu'il reconnaît.
    • Toutes les directives découvertes sont compilées récursivement et leurs linkfonctions sont collectées.
    • Ensuite, toutes les linkfonctions sont enveloppées dans une nouvelle linkfonction et renvoyées sous la forme l.
  • Enfin, nous fournissons une scopefonction à cette fonction l(lien) qui exécute en outre les fonctions de lien encapsulées avec celle-ci scopeet leurs éléments correspondants.

    l(scope)

  • Cela ajoute le en templatetant que nouveau nœud au DOMet appelle controllerce qui ajoute ses montres à la portée qui est partagée avec le modèle dans DOM.

entrez la description de l'image ici

En comparant la compilation vs lien vs contrôleur :

  • Chaque directive n'est compilée qu'une seule fois et la fonction de liaison est conservée pour être réutilisée. Par conséquent, s'il y a quelque chose qui s'applique à toutes les instances d'une directive, celle-ci doit être effectuée à l'intérieur de la compilefonction de la directive .

  • Maintenant, après la compilation, nous avons une linkfonction qui est exécutée tout en attachant le modèle au DOM . Nous effectuons donc tout ce qui est spécifique à chaque instance de la directive. Par exemple: attacher des événements , muter le modèle en fonction de la portée , etc.

  • Enfin, le contrôleur est censé être disponible pour être en direct et réactif pendant que la directive fonctionne sur le DOM(après avoir été attaché). Par conséquent:

    (1) Après avoir configuré la vue [ V ] (ie modèle) avec lien. $scopeest notre [ M ] et $controllerest notre [ C ] dans MVC

    (2) Profitez de la liaison bidirectionnelle avec $ scope en configurant des montres.

    (3) les $scopemontres devraient être ajoutées dans le contrôleur, car c'est ce qui regarde le modèle pendant l'exécution.

    (4) Enfin, controllerest également utilisé pour pouvoir communiquer entre les directives connexes. (Comme myTabsexemple dans https://docs.angularjs.org/guide/directive )

    (5) Il est vrai que nous aurions pu faire tout cela aussi dans la linkfonction, mais c'est une question de séparation des préoccupations .

Par conséquent, nous avons enfin les éléments suivants qui s'adaptent parfaitement à toutes les pièces:

entrez la description de l'image ici

Yugal Jindle
la source
5
J'ai également trouvé cet article utile pour comprendre l'ordre d'exécution ici: Le détail des fonctions de compilation et de liaison dans les directives AngularJS
BobbyA
4
Grande explication. Je voudrais mentionner que le contrôleur est appelé avant la fonction de liaison.
jsbisht
38
le contrôleur est exécuté avant le lien
Royi Namir
10
Cela me rend furieux que Stack Overflow exige que les modifications soient d'au moins 6 caractères, ce qui ne me permet pas de corriger l'orthographe de let dans cette réponse.
user1886323
79

Pourquoi les contrôleurs sont nécessaires

La différence entre linket controllerentre en jeu lorsque vous souhaitez imbriquer des directives dans votre DOM et exposer les fonctions API de la directive parent aux directives imbriquées.

De la documentation :

Meilleure pratique: utilisez le contrôleur lorsque vous souhaitez exposer une API à d'autres directives. Sinon, utilisez le lien.

Disons que vous voulez avoir deux directives my-formet my-text-inputque vous voulez que la my-text-inputdirective n'apparaisse qu'à l'intérieur my-formet nulle part ailleurs.

Dans ce cas, vous direz lors de la définition de la directive my-text-inputqu'elle requiert un contrôleur de l' parentélément DOM en utilisant l'argument de besoin, comme ceci: require: '^myForm'. Maintenant, le contrôleur de l'élément parent sera injecteddans la linkfonction comme quatrième argument suivant $scope, element, attributes. Vous pouvez appeler des fonctions sur ce contrôleur et communiquer avec la directive parent.

De plus, si un tel contrôleur n'est pas trouvé, une erreur sera générée.

Pourquoi utiliser le lien

Il n'y a pas vraiment besoin d'utiliser la linkfonction si l'on définit le controllerpuisque le $scopeest disponible sur le controller. De plus, tout en définissant à la foislink et controller, il faut faire attention à l'ordre d'invocation des deux ( controllerest exécuté avant).

Cependant, conformément à la méthode angulaire , la plupart des manipulations DOM et de la liaison bidirectionnelle $watcherssont généralement effectuées dans la linkfonction tandis que l'API pour les enfants et la $scopemanipulation sont effectuées dans le controller. Ce n'est pas une règle stricte et rapide, mais cela rendra le code plus modulaire et aidera à séparer les préoccupations (le contrôleur maintiendra l' directiveétat et la linkfonction conservera les DOMliaisons + externes).

musically_ut
la source
C'est génial. Maintenant, pouvez-vous m'aider avec la deuxième partie de la question?
Yugal Jindle
Je veux dire, puisque nous avions le contrôleur qui aurait pu être utilisé pour communiquer avec d'autres directives. Alors, quel était le besoin de link?
Yugal Jindle
1
Votre réponse ne répond pas en quelque sorte à la question réelle.
Yugal Jindle
1
Y a-t-il des problèmes qui se produisent lorsque nous définissons un controller? Pourquoi vais-je vouloir inventer une toute nouvelle fonction juste pour éviter de définir un contrôleur?
Yugal Jindle
1
il semble que le lien de @scalaGirl ne fonctionne plus
Minato
17

La controllerfonction / objet représente un contrôleur de vue de modèle d'abstraction (MVC). Bien qu'il n'y ait rien de nouveau à écrire sur MVC, c'est toujours le plus grand avantage d'angular: diviser les préoccupations en plus petits morceaux. Et voilà, rien de plus, donc si vous devez réagir sur les Modelchangements à venir de Viewl' Controllerest la bonne personne pour faire ce travail.

L'histoire de la linkfonction est différente, elle vient d'une perspective différente de celle de MVC. Et c'est vraiment essentiel, une fois qu'on veut franchir les frontières d'un controller/model/view (modèle) .

Commençons par les paramètres passés dans la linkfonction:

function link(scope, element, attrs) {
  • scope est un objet scope angulaire.
  • L'élément est l'élément enveloppé dans jqLite auquel cette directive correspond.
  • attrs est un objet avec les noms d'attributs normalisés et leurs valeurs correspondantes.

Pour mettre le linkdans le contexte, nous devons mentionner que toutes les directives passent par ces étapes du processus d'initialisation: Compiler , Lier . Un extrait de Brad Green et Shyam Seshadri livre Angular JS :

Phase de compilation (sœur du lien, mentionnons-la ici pour avoir une image claire):

Dans cette phase, Angular parcourt le DOM pour identifier toutes les directives enregistrées dans le modèle. Pour chaque directive, il transforme ensuite le DOM en fonction des règles de la directive (modèle, remplacer, transclure, etc.) et appelle la fonction de compilation si elle existe. Le résultat est une fonction de modèle compilée,

Phase de liaison :

Pour rendre la vue dynamique, Angular exécute ensuite une fonction de lien pour chaque directive. Les fonctions de liaison créent généralement des écouteurs sur le DOM ou le modèle. Ces auditeurs gardent la vue et le modèle synchronisés à tout moment.

Un bel exemple comment utiliser le linkpourrait être trouvé ici: Création de directives personnalisées . Voir l'exemple: Création d'une directive qui manipule le DOM , qui insère une "date-heure" dans la page, actualisée toutes les secondes.

Juste un extrait très court de cette riche source ci-dessus, montrant la vraie manipulation avec DOM. Il y a une fonction accrochée au service $ timeout, et elle est également effacée dans son appel de destructeur pour éviter les fuites de mémoire

.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
la source
3
Vous semblez avoir comparé compileret link. Ils se demandent pourquoi linkalors que nous avions déjàcontroller
Yugal Jindle
J'ai étendu la réponse pour décrire même le contrôleur plus en détail. Maintenant, les concepts du controllervs linkdevraient être plus clairs ...
Radim Köhler
1
Je peux chercher à me contenter de cette explication. Mais cela semble un peu flou. Ce serait formidable si quelqu'un de l'équipe angulaire elle-même pouvait parler en son nom, projetant où le voyaient-ils aller - au linkou au controller.
Yugal Jindle
1
C'est la seule partie que je veux comprendre (quand n'est-ce pas suffisant?). De plus, je profite de tous les avantages de l'angulaire controlleret linkest relativement moche. Donc, l'équipe angulaire doit avoir une bonne raison au lieu d'une simple option.
Yugal Jindle
1
Question: Quand le contrôleur n'est pas suffisant? Rép: Lorsque vous avez besoin d'une expérience hors Angular, par exemple pour utiliser un plugin JQuery ou utiliser la fonctionnalité JQlite comme mentionné dans le document ( docs.angularjs.org/api/ng/function/angular.element:) , alors vous aurez besoin link
Hasteq