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 fonctionlink
appelée avant les directives enfantscompile
sont 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-repeat
de 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-repeat
de 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.).