web-dev-qa-db-fra.com

Angular JS: Quelle est la nécessité de la fonction de liaison de la directive alors que nous avions déjà son contrôleur avec une portée?

Je dois effectuer certaines opérations sur le scope et le template. Il semble que je puisse le faire dans la fonction link ou dans la fonction controller (puisque les deux ont accès à la portée).

À quel moment dois-je utiliser la fonction link 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 */ }
    };
}

De plus, je comprends que link est le monde non angulaire. Donc, je peux utiliser $watch, $digest et $apply.

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

192
Yugal Jindle

Après mes luttes initiales avec les fonctions link et controller et en en lisant beaucoup, je pense que j’ai maintenant le répondre.

Commençons par à comprendre ,

Comment fonctionnent les directives angular en quelques mots:

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

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

  • Maintenant, cette templateString est enveloppée comme un élément angulaire

    var el = angular.element(templateString);

  • Avec el, nous le compilons maintenant avec $compile pour récupérer la fonction link .

    var l = $compile(el)

    Voici ce qui se passe,

    • $compile parcourt l'intégralité du modèle et collecte toutes les directives qu'il reconnaît.
    • Toutes les directives découvertes sont compilées de manière récursive et leurs fonctions link sont collectées.
    • Ensuite, toutes les fonctions link sont encapsulées dans une nouvelle fonction link et renvoyées sous la forme l.
  • Enfin, nous fournissons la fonction scope à cette fonction l (lien) qui exécute ensuite les fonctions de lien encapsulées avec ce scope et leurs éléments correspondants.

    l(scope)

  • Ceci ajoute la template comme nouveau nœud à la DOM et appelle controller qui ajoute ses surveillances à la portée qui est partagé avec le modèle dans DOM.

enter image description here

Comparer compiler vs lien vs contrôleur :

  • Chaque directive est compilée une seule fois et la fonction link est conservée pour utilisation. Par conséquent, s'il existe quelque chose qui s'applique à toutes les instances d'une directive, cela doit être effectué dans la fonction compile de la directive.

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

  • Enfin, le contrôleur doit être disponible pour être actif et réactif pendant que la directive fonctionne sur la DOM (après avoir été attaché). Donc:

    (1) Après avoir configuré la vue [V] (c'est-à-dire un modèle) avec un lien. $scope est notre [M] et $controller est notre [C] dans MVC

    (2) Profitez de la liaison à 2 voies avec $ scope en mise en place des montres.

    (3) $scope on s'attend à ce que des montres soient ajoutées au contrôleur car c'est ce qui surveille le modèle pendant l'exécution.

    (4) Enfin, controller est également utilisé pour pouvoir communiquer entre les directives associées. (Comme myTabs exemple dans https://docs.angularjs.org/guide/directive )

    (5) Il est vrai que nous aurions pu faire tout cela dans la fonction link, mais il en va de même la séparation des problèmes .

Par conséquent, enfin, nous avons ce qui suit qui convient parfaitement à toutes les pièces:

enter image description here

291
Yugal Jindle

Pourquoi les contrôleurs sont nécessaires

La différence entre link et controller entre en jeu lorsque vous souhaitez imbriquer des directives dans votre DOM et exposer des fonctions API de la directive parente à celles imbriquées.

De la docs :

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

Supposons que vous souhaitiez avoir deux directives my-form et my-text-input et que vous souhaitiez que la directive my-text-input n'apparaisse que dans my-form et nulle part ailleurs.

Dans ce cas, vous direz lors de la définition de la directive my-text-input qu'elle requiert un contrôleur de l'élément DOM parent à l'aide de l'élément require argument , comme ceci: require: '^myForm'. Maintenant, le contrôleur de l'élément parent sera injected dans la fonction link en tant que quatrième argument, après $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 du tout

Il n’est pas vraiment nécessaire d’utiliser la fonction link si l’on définit le controller puisque le $scope est disponible sur le controller. De plus, lors de la définition de link et de controller, il convient de faire attention à l'ordre d'invocation des deux (controller est exécuté auparavant).

Cependant, conformément à la méthode angulaire , la plupart des manipulations DOM et des liaisons bidirectionnelles à l'aide de $watchers sont généralement effectuées dans la fonction link, tandis que L'API pour les enfants et la manipulation de $scope se font dans le controller. Ce n'est pas une règle absolue, mais cela rendra le code plus modulaire et facilitera la séparation des problèmes (le contrôleur conservera l'état directive et la fonction link conservera les liaisons DOM + extérieures).

72
musically_ut

La fonction/objet controller représente un contrôleur d'abstraction modèle-vue-contrôleur (MVC). Bien qu’il n’y ait rien de nouveau à écrire sur MVC, c’est toujours l’avantage le plus significatif d’angularité: diviser les préoccupations en plusieurs parties. Et voilà, rien de plus, donc si vous devez réagir sur Model changements venant de View la Controller est la bonne personne à faire ce travail.

L'histoire de la fonction link est différente, elle vient d'une perspective différente de celle de MVC. Et est vraiment essentiel, une fois que nous voulons franchir les limites d'un controller/model/view (modèle) .

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

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

Pour placer la link dans le contexte, il convient de mentionner que toutes les directives suivent cette étape du processus d’initialisation: Compile , Lien . Un extrait de livre de Brad Green et Shyam Seshadri Angular JS :

Phase de compilation (une soeur de link, mentionnons-le ici pour avoir une image claire):

Au cours de cette phase, Angular guide 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 celle-ci (template, replace, transclude, 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 lien 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.

Voici un exemple intéressant d'utilisation de la variable link: Création de directives personnalisées . Voir l'exemple: Création d'une directive manipulant le DOM , qui insère une "date-heure" dans la page, actualisée toutes les secondes.

Juste un très court extrait de la source riche ci-dessus, montrant la véritable manipulation avec DOM. Il y a une fonction accrochée au service $ timeout et elle est également effacée dans son appel destructor 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);
 });

 ...
17
Radim Köhler