Lien vs compilation vs contrôleur


529

Lorsque vous créez une directive, vous pouvez mettre du code dans le compilateur, la fonction de liaison ou le contrôleur.

Dans les documents, ils expliquent que:

  • les fonctions de compilation et de liaison sont utilisées dans différentes phases du cycle angulaire
  • les contrôleurs sont partagés entre les directives

Cependant, pour moi, ce n'est pas clair, quel type de code devrait aller où.

Par exemple: Puis-je créer des fonctions dans la compilation et les avoir attachées à la portée dans le lien ou seulement attacher des fonctions à la portée dans le contrôleur?

Comment les contrôleurs sont-ils partagés entre les directives, si chaque directive peut avoir son propre contrôleur? Les contrôleurs sont-ils vraiment partagés ou s'agit-il simplement des propriétés d'étendue?




1
J'ai écrit un article avec un schéma du cycle de vie de la directive (phase de création). Peut-être que cela aide quelqu'un: filimanjaro.com/2014/…
moyenne Joe

Réponses:


470

Compiler :

C'est la phase où Angular compile réellement votre directive. Cette fonction de compilation est appelée une seule fois pour chaque référence à la directive donnée. Par exemple, supposons que vous utilisez la directive ng-repeat. ng-repeat devra rechercher l'élément auquel il est attaché, extraire le fragment html auquel il est attaché et créer une fonction de modèle.

Si vous avez utilisé des poignées, des modèles de soulignement ou l'équivalent, c'est comme compiler leurs modèles pour extraire une fonction de modèle. À cette fonction de modèle, vous transmettez des données et la valeur de retour de cette fonction est le code HTML avec les données aux bons endroits.

La phase de compilation est cette étape dans Angular qui renvoie la fonction de modèle. Cette fonction de modèle en angulaire est appelée la fonction de liaison.

Phase de liaison:

La phase de liaison est l'endroit où vous attachez les données ($ scope) à la fonction de liaison et elle devrait vous renvoyer le code HTML lié. Puisque la directive spécifie également où va ce HTML ou ce qu'il change, il est déjà bon d'aller. Il s'agit de la fonction dans laquelle vous souhaitez apporter des modifications à l'html lié, c'est-à-dire à l'html qui a déjà les données qui lui sont attachées. En angulaire, si vous écrivez du code dans la fonction de liaison, c'est généralement la fonction post-lien (par défaut). C'est une sorte de rappel qui est appelé après que la fonction de liaison a lié les données au modèle.

Manette :

Le contrôleur est un endroit où vous mettez dans une logique spécifique à la directive. Cette logique peut également entrer dans la fonction de liaison, mais vous devrez alors mettre cette logique sur la portée pour la rendre "partageable". Le problème avec cela est que vous corrompriez alors la portée avec vos trucs de directives, ce qui n'est pas vraiment quelque chose qui est attendu. Alors, quelle est l'alternative si deux directives veulent se parler / coopérer? Bien sûr, vous pouvez mettre toute cette logique dans un service, puis faire dépendre ces deux directives de ce service, mais cela ne fait qu'apporter une dépendance supplémentaire. L'alternative est de fournir un contrôleur pour cette portée (généralement une portée isolée?), Puis ce contrôleur est injecté dans une autre directive lorsque cette directive "requiert" l'autre.


67
Pour clarifier: compiler compile le modèle à utiliser tout au long de la page. L'éditeur de liens est lié à chaque instance. Droite? Le contrôleur fonctionne ensuite entre les instances.
Zlatko

4
@CMCDragonkai pour chaque controllerfonction de directive est exécuté après la compilation, mais avant pre-link dans une branche d'arbre DOM locale. De plus controller, les pre-linkfonctions sont exécutées en traversant la branche DOM locale de manière descendante . Après cela post-linkest exécuté de manière ascendante .
Artem Platonov

9
Ce n'est qu'un gâchis si vous ne le comprenez pas. Il y a une raison pour qu'il fasse ce qu'il fait.
demisx

3
C'est la bonne réponse technique, cependant, je reste avec des questions sur le moment où je devrais utiliser la fonction de lien.
Nicholas Marshall

2
Allons-nous utiliser controllerau lieu de linkpartout? De sorte que je n'ai pas besoin de changer le code à l'avenir si la méthode doit être partagée ou une logique à introduire?. Y a-t-il des pièges à utiliser controllertout le temps au lieu du lien?
JPS

99

Je voulais également ajouter ce que le livre O'Reily AngularJS de l'équipe Google a à dire:

Contrôleur - Créez un contrôleur qui publie une API pour communiquer entre les directives. Un bon exemple est communication directive à directive

Lien - Modifiez par programmation les instances d'élément DOM résultantes, ajoutez des écouteurs d'événements et configurez la liaison de données.

Compiler - Modifiez par programme le modèle DOM pour les fonctionnalités sur des copies d'une directive, comme lorsqu'il est utilisé dans ng-repeat. Votre fonction de compilation peut également renvoyer des fonctions de lien pour modifier les instances d'élément résultantes.


Votre lien thinkster.io ne peut pas être regardé sans payer. Pas mon lien, mais c'est peut-être plus approprié: toddmotto.com/directive-to-directive-communication-with-require
R. van Twisk

51

A directivevous permet d'étendre le vocabulaire HTML de manière déclarative pour créer des composants Web. L' ng-appattribut est une directive, tout comme le sont ng-controllertous les ng- prefixed attributes. Les directives peuvent être attributes, tagsou même class names, comments.

Comment naissent les directives ( compilationet instantiation)

Compiler: nous utiliserons la compilefonction à la fois dans manipulatele DOM avant son rendu et retournerons une linkfonction (qui gérera la liaison pour nous). C’est aussi l’endroit où mettre toutes les méthodes qui doivent être partagées avec tous lesinstances de cette directive.

lien: Nous utiliserons la linkfonction pour enregistrer tous les écouteurs sur un élément DOM spécifique (qui est cloné à partir du modèle) et configurer nos liaisons à la page.

S'ils compile()étaient définis dans la fonction, ils n'auraient été définis qu'une seule fois (ce qui est souvent ce que vous voulez). S'ils link()étaient définis dans la fonction, ils le seraient à chaque fois que l'élément HTML est lié aux données de l' objet.

<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){

     }
   };
});

Compilerenvoie la fonction preet la postliaison. Dans la fonction de pré-lien, nous avons le modèle d'instance et également la portée de lacontroller , mais le modèle n'est pas lié à la portée et n'a toujours pas de contenu transclu.

Postla fonction de lien est l'endroit où le lien de publication est la dernière fonction à exécuter. Maintenant, le transclusionest terminé the template is linked to a scope, et le view will update with data bound values after the next digest cycle. L' linkoption n'est qu'un raccourci pour configurer une post-linkfonction.

contrôleur: Le contrôleur de directive peut être passé à une autre phase de liaison / compilation de directive. Il peut être injecté dans d'autres directions comme moyen à utiliser dans la communication inter-directive.

Vous devez spécifier le nom de la directive à exiger - Elle doit être liée au même élément ou à son parent. Le nom peut être préfixé avec:

?  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.

Utilisez un crochet [‘directive1′, ‘directive2′, ‘directive3′]pour exiger un contrôleur à directives multiples.

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
vous avez mentionné que vous avez montré comment obtenir le parentDirectiveCtrl dans le contrôleur de l'enfant ... cet exemple, l'enfant n'a pas de contrôleur, mais plutôt une fonction de liaison ... Je ne suis pas bloqué sur ce problème actuellement, donc il se peut qu'il ne soit pas si important, mais une question curieuse.
alockwood05

13

De plus, une bonne raison d'utiliser une fonction contrôleur vs lien (car ils ont tous les deux accès à la portée, à l'élément et aux attrs) est que vous pouvez transmettre n'importe quel service ou dépendance disponible à un contrôleur (et dans n'importe quel ordre), tandis que vous ne pouvez pas le faire avec la fonction de lien. Remarquez les différentes signatures:

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

contre.

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

2
Veuillez laisser un commentaire pour expliquer votre point lorsque vous réduisez une réponse. Merci
svassr

53
Je n'étais pas downvoter, mais ce n'est pas strictement correcte car vous pouvez toujours injecter toute dépendance nécessaire dans la directive elle - même, par exemple: module.directive('myDirective', function($window) { etc.... Vous pouvez ensuite y accéder depuis l'intérieur de la fonction de lien.
Mike Chamberlain

1
cela semble être tout simplement incorrect car vous pouvez injecter des services dans la fonction de liaison
Code Whisperer

1
@JoshRibakoff Le résultat final est le même, vous avez accès au service dans la fonction de lien. Peu importe qu'elle soit déclarée ou non dans les arguments de la fonction. À cet égard, Mike Chamberlain a raison
Connor Wyatt

1
@ cwyatt1 Je corrigeais le langage, le plnkr ne montre pas l'injection dans une fonction link () car ce n'est pas une fonctionnalité qu'Angular a. Vous pourriez penser que je suis pédant, mais les commentaires de métamatts soulignent déjà de nombreuses différences importantes entre ce que fait ce plunkr et ce que fait l'injection à un contrôleur. Le PO demande quelles sont les différences, et il y a des différences.
Josh Ribakoff

10

ceci est un bon exemple pour comprendre les phases de la directive 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
Pourriez-vous expliquer pourquoi cet exemple de code aiderait à comprendre la différence entre link, compileet controller?
cel sharp

savez-vous comment une requiredirective d peut être injectée dans le contrôleur d'une directive dépendante?
alockwood05

Vous codepen exemple: Erreur non interceptée: [$ injector: modulerr] Échec de l'instanciation du module myapp en raison de: Erreur: [$ injector: impr] Fournisseur inconnu: slngStylePrelinkProvider
rofrol

7
  • compile : utilisé lorsque nous devons modifier le modèle de directive, comme ajouter une nouvelle expression, ajouter une autre directive à l'intérieur de cette directive
  • contrôleur : utilisé lorsque nous avons besoin de partager / réutiliser les données $ scope
  • link : c'est une fonction qui nous a servi lorsque nous avons besoin d'attacher un gestionnaire d'événements ou de manipuler DOM.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.