Directives angulaires - quand et comment utiliser compile, controller, pre-link et post-link [closed]
Lorsqu'on écrit une directive angulaire, on peut utiliser l'une des fonctions suivantes pour manipuler le comportement, le contenu et l'apparence de L'élément sur lequel la directive est déclarée:
- compiler
- contrôleur
- pré-link
- post-link
il semble y avoir une certaine confusion quant à la fonction qui devrait être utilisée. Cette question couvre:
Directive de base
- Comment déclarer les différentes fonctions?
- Quelle est la différence entre un modèle de source et un exemple de modèle ?
- dans quel ordre les fonctions de directive sont exécutées?
- Quoi d'autre qui se passe entre ces appels de fonction?
fonction nature, do's and non's
questions connexes:
- Directive: link vs compiler vs controller .
- différence entre les fonctions 'controller', 'link' et 'compile' lors de la définition d'un angle.js directive .
- Quelle est la différence entre la compilation et de la fonction de lien dans angularjs .
- différence entre l'élément pré-et post-compilation dans les directives AngularJS? .
- Angular JS Directive - Modèle, compiler ou un lien? .
- afficher le lien vs pré lien en Angular js directives .
8 réponses
dans quel ordre les fonctions de directive sont exécutées?
pour une directive unique
basé sur le suivant Pluk , considérez le balisage HTML suivant:
<body>
<div log='some-div'></div>
</body>
avec la déclaration directive suivante:
myApp.directive('log', function() {
return {
controller: function( $scope, $element, $attrs, $transclude ) {
console.log( $attrs.log + ' (controller)' );
},
compile: function compile( tElement, tAttributes ) {
console.log( tAttributes.log + ' (compile)' );
return {
pre: function preLink( scope, element, attributes ) {
console.log( attributes.log + ' (pre-link)' );
},
post: function postLink( scope, element, attributes ) {
console.log( attributes.log + ' (post-link)' );
}
};
}
};
});
la sortie de la console sera:
some-div (compile)
some-div (controller)
some-div (pre-link)
some-div (post-link)
Nous pouvons voir que compile est exécuté en premier, puis controller , puis pre-link et le dernier est post-link .
pour les directives imbriquées
Note: ce qui suit ne s'applique pas aux directives qui rendent leurs enfants dans leur fonction de lien. Plusieurs directives angulaires le font (comme ngIf, ngRepeat, ou toute autre directive avec
transclude). Ces directives auront nativement leur fonctionlinkappelée avant les directives enfantscompilesont appelées.
le balisage HTML original est souvent fait d'éléments imbriqués, chacun avec sa propre directive. Comme dans le markup suivant (Voir plunk ):
<body>
<div log='parent'>
<div log='..first-child'></div>
<div log='..second-child'></div>
</div>
</body>
la sortie de la console ressemblera à ceci:
// The compile phase
parent (compile)
..first-child (compile)
..second-child (compile)
// The link phase
parent (controller)
parent (pre-link)
..first-child (controller)
..first-child (pre-link)
..first-child (post-link)
..second-child (controller)
..second-child (pre-link)
..second-child (post-link)
parent (post-link)
nous pouvons distinguer deux phases ici - le compiler phase et le lien phase.
la phase de compilation
quand le DOM est chargé angulaire commence la phase de compilation, où il traverse le markup top-down, et appelle compile sur toutes les directives. Graphiquement, nous pourrions l'exprimer ainsi:
il est peut-être important de mentionner qu'à ce stade, les templates que la fonction de compilation obtient sont les templates source (pas le template d'instance).
Le lien "de la phase 1519540920"
les instances DOM sont souvent simplement le résultat d'un modèle de source rendu au DOM, mais elles peuvent être créées par ng-repeat , ou introduites à la volée.
chaque fois qu'une nouvelle instance d'un élément avec une directive est rendue au DOM, la phase de lien commence.
dans cette phase, les appels angulaires controller , pre-link , itère les enfants, et l'appel post-link sur toutes les directives, comme ceci:
que se passe-t-il d'autre entre ces appels de fonction?
les diverses fonctions de la directive sont exécutées à l'intérieur de deux autres fonctions angulaires appelées $compile (où la directive compile est exécutée) et une fonction interne appelée nodeLinkFn (où les directives controller , preLink et postLink sont exécutées). Diverses choses se produisent dans la fonction angulaire avant et après les fonctions de directive sont appelées. Peut-être le plus notamment est l'enfant de la récursivité. L'illustration simplifiée suivante montre les étapes clés dans les phases de compilation et de lien:
pour démontrer ces étapes, utilisons le balisage HTML suivant:
<div ng-repeat="i in [0,1,2]">
<my-element>
<div>Inner content</div>
</my-element>
</div>
avec la directive suivante:
myApp.directive( 'myElement', function() {
return {
restrict: 'EA',
transclude: true,
template: '<div>{{label}}<div ng-transclude></div></div>'
}
});
compiler
L'API compile ressemble à cela:
compile: function compile( tElement, tAttributes ) { ... }
souvent, les paramètres sont préfixés avec t pour signifier les éléments et attributs fournis sont ceux du modèle source, plutôt que celui de l'instance.
avant l'appel à compile contenu transcluse (le cas échéant) est supprimé, et le modèle est appliqué à la marge. Ainsi, l'élément fourni à la fonction compile ressemblera à ceci:
<my-element>
<div>
"{{label}}"
<div ng-transclude></div>
</div>
</my-element>
notez que le contenu transclusifié n'est pas réintroduit à ce point.
suite à l'appel à la directive .compile , Angular traversera tous les éléments enfants, y compris ceux qui peuvent avoir été introduits par la directive (les éléments de modèle, par exemple).
création D'Instance
dans notre cas, trois instances du modèle de source ci-dessus seront créées (par
). Ainsi, la séquence suivante sera exécutée trois fois, une fois par instance.
contrôleur
L'API controller implique:
controller: function( $scope, $element, $attrs, $transclude ) { ... }
entrant dans la phase de liaison, la fonction de liaison retournée via $compile est maintenant fournie avec une portée.
tout d'abord, la fonction link crée une portée enfant ( scope: true ) ou une portée isolée ( scope: {...} ) si demandé.
le contrôleur est alors exécuté, à condition que la portée de la instance de l'élément.
Pré-link
L'API pre-link ressemble à cela:
function preLink( scope, element, attributes, controller ) { ... }
il ne se passe pratiquement rien entre l'appel à la fonction .controller de la directive et la fonction .preLink . Angular continue de fournir des recommandations quant à la façon d'utiliser chacune.
après l'appel .preLink , la fonction de lien traverse chaque élément enfant-appelant la fonction de lien correcte et lui attacher le champ d'application actuel (qui sert de champ parent pour les éléments enfants).
Post-link
L'API post-link est similaire à celle de la fonction pre-link :
function postLink( scope, element, attributes, controller ) { ... }
peut-être vaut-il la peine de noter qu'une fois que la fonction .postLink d'une directive est appelée, le processus de lien de tous ses éléments enfants a terminé, y compris toutes les fonctions .postLink des enfants.
cela signifie qu'au moment où .postLink est appelé, les enfants sont 'vivants' sont prêts. Cela comprend:
- liaison de données
- transclusion appliquée
- domaine d'application joint
le modèle à ce stade ressemblera ainsi:
<my-element>
<div class="ng-binding">
"{{label}}"
<div ng-transclude>
<div class="ng-scope">Inner content</div>
</div>
</div>
</my-element>
Comment déclarer les différentes fonctions?
compiler, Controller, Pre-link & Post-link
si l'on doit utiliser les quatre fonctions, la directive suivra ce formulaire:
myApp.directive( 'myDirective', function () {
return {
restrict: 'EA',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
compile: function compile( tElement, tAttributes, transcludeFn ) {
// Compile code goes here.
return {
pre: function preLink( scope, element, attributes, controller, transcludeFn ) {
// Pre-link code goes here
},
post: function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
}
};
}
};
});
Notice that compile retourne un objet contenant à la fois les fonctions pré-lien et post-lien; En jargon angulaire nous disons que la fonction compile retourne une template function .
Compiler, Controller & Post-link
si pre-link n'est pas nécessaire, la fonction compiler peut simplement retourner la fonction post-link au lieu d'un objet de définition, comme ceci:
myApp.directive( 'myDirective', function () {
return {
restrict: 'EA',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
compile: function compile( tElement, tAttributes, transcludeFn ) {
// Compile code goes here.
return function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
};
}
};
});
parfois, on souhaite ajouter une méthode compile , après que la méthode link (post) a été définie. Pour cela, on peut utiliser:
myApp.directive( 'myDirective', function () {
return {
restrict: 'EA',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
compile: function compile( tElement, tAttributes, transcludeFn ) {
// Compile code goes here.
return this.link;
},
link: function( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
}
};
});
Controller & Post-link
si aucune fonction de compilation n'est nécessaire, on peut passer complètement sa déclaration et fournir la fonction post-link sous la propriété link de l'objet de configuration de la directive:
myApp.directive( 'myDirective', function () {
return {
restrict: 'EA',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
link: function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
},
};
});
Pas de contrôleur
dans l'un des exemples ci-dessus, on peut simplement supprimer la fonction controller si elle n'est pas nécessaire. Ainsi, par exemple, si seulement la fonction post-link est nécessaire, on peut utiliser:
myApp.directive( 'myDirective', function () {
return {
restrict: 'EA',
link: function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
},
};
});
Quelle est la différence entre un modèle de source et un exemple de modèle ?
le fait que L'angle autorise la manipulation DOM signifie que le balisage d'entrée dans le processus de compilation diffère parfois de la sortie. En particulier, certains markup d'entrée peuvent être clonés quelques fois (comme avec ng-repeat ) avant d'être rendus au DOM.
la terminologie angulaire est un peu incohérente, mais il distingue encore entre deux types de majorations:
- Source template - le balisage à cloner, si nécessaire. S'il est cloné, ce markup ne sera pas rendu au DOM.
- Instance template - le markup réel à rendre au DOM. Si le clonage est impliqué, chaque instance sera un clone.
le balisage suivant démontre ceci::
<div ng-repeat="i in [0,1,2]">
<my-directive>{{i}}</my-directive>
</div>
la source html définit
<my-directive>{{i}}</my-directive>
, qui sert de modèle source.
mais comme il est enveloppé dans une directive ng-repeat , ce modèle source sera cloné (3 fois dans notre cas). Ces clones sont des modèles d'instance, chacun apparaîtra dans le DOM et sera lié à la portée pertinente.
compiler function
la fonction compile de chaque directive n'est appelée qu'une seule fois, lorsque des bootstraps angulaires.
officiellement, c'est l'endroit pour effectuer des manipulations (source) de gabarit qui n'impliquent pas la portée ou la liaison de données.
principalement, ceci est fait à des fins d'optimisation; considérons le markup suivant:
<tr ng-repeat="raw in raws">
<my-raw></my-raw>
</tr>
la directive <my-raw> rendra set de DOM markup. Donc nous pouvons soit:
- permet à
ng-repeatde dupliquer le modèle source (<my-raw>), puis de modifier le balisage de chaque modèle d'instance (en dehors de la fonctioncompile). - modifier le modèle de source pour impliquer le balisage désiré (dans la fonction
compile), puis permettre àng-repeatde le dupliquer.
S'il y a 1000 articles dans le raws collecte, cette dernière option peut être plus rapide que la première.
:
- manipule le markup pour qu'il serve de modèle aux instances (clones).
Ne pas
- Joindre les gestionnaires d'événements.
- inspecter les éléments pour enfants.
- configurer les observations sur les attributs.
- régler les montres sur la lunette.
Post-lien de la fonction
lorsque la fonction post-link est appelée, Toutes les étapes précédentes ont eu lieu - liaison, transclusion, etc.
c'est typiquement un endroit pour manipuler davantage le DOM Rendu.
:
- manipule des éléments DOM (rendus, et donc instanciés).
- Joindre les gestionnaires d'événements.
- inspecter les éléments enfants.
- configurer les observations sur les attributs.
- réglez les montres sur la lunette.
fonction contrôleur
la fonction controller de chaque directive est appelée chaque fois qu'un nouvel élément connexe est instancié.
officiellement, la fonction controller est où un:
- définit la logique (les méthodes) du contrôleur qui peut être partagée entre les contrôleurs.
- initie les variables de champ.
encore une fois, il est important de se rappeler que si le la directive comporte un champ d'application isolé, les biens qui en héritent ne sont pas encore disponibles.
:
- Définir la logique du contrôleur
- Lancer la portée des variables
à Ne pas faire:
- inspecter les éléments enfants (ils ne peuvent pas encore être rendus, liés à la portée, etc.).
Pré-lien de la fonction
la fonction pre-link de chaque directive est appelée chaque fois qu'un nouvel élément connexe est instancié.
comme nous l'avons vu précédemment dans la section ordre de compilation, les fonctions pre-link sont appelées" parent-puis-enfant", tandis que les fonctions post-link sont appelées child-then-parent .
la fonction pre-link est rarement utilisée, mais peut être utile dans des scénarios spéciaux; par exemple, lorsqu'un contrôleur enfant s'enregistre avec le contrôleur parent, mais l'enregistrement doit être parent-then-child ( ngModelController fait les choses de cette façon).
à Ne pas faire:
- inspecter les éléments enfants (ils ne peuvent pas encore être rendus, liés à la portée, etc.).