Lors de l’écriture d’une directive angular, on peut utiliser l’une des fonctions suivantes pour manipuler le comportement, le contenu et l’apparence du DOM sur lequel la directive est déclarée:
Il semble y avoir une certaine confusion quant à la fonction à utiliser. Cette question couvre:
Basé sur le plunk suivant, considérez le balisage HTML suivant:
Avec la déclaration de directive suivante:
myApp.directive('log', function() { return { controller: function( $scope, $element, $attrs, $transclude ) { console.log( $attrs.log + ' (controller)' ); }, comstack: function comstack( tElement, tAtsortingbutes ) { console.log( tAtsortingbutes.log + ' (comstack)' ); return { pre: function preLink( scope, element, atsortingbutes ) { console.log( atsortingbutes.log + ' (pre-link)' ); }, post: function postLink( scope, element, atsortingbutes ) { console.log( atsortingbutes.log + ' (post-link)' ); } }; } }; });
La sortie de la console sera:
some-div (comstack) some-div (controller) some-div (pre-link) some-div (post-link)
Nous pouvons voir que la comstack
est exécutée en premier, puis le controller
, puis le pre-link
et le dernier est post-link
.
Remarque: Ce qui suit ne s’applique pas aux directives qui rendent leurs enfants dans leur fonction de lien. De nombreuses directives angulars le font (comme ngIf, ngRepeat ou toute directive avec
transclude
). Ces directives auront nativement leur fonction delink
appelée avant que leurcomstack
enfant ne soit appelée.
Le balisage HTML d’origine est souvent composé d’éléments nesteds, chacun avec sa propre directive. Comme dans le balisage suivant (voir plunk ):
La sortie de la console ressemblera à ceci:
// The comstack phase parent (comstack) ..first-child (comstack) ..second-child (comstack) // 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)
On peut distinguer ici deux phases – la phase de compilation et la phase de liaison .
Lorsque le DOM est chargé, Angular démarre la phase de compilation, où il parcourt le balisage, et les appels sont comstack
sur toutes les directives. Graphiquement, nous pourrions l’exprimer ainsi:
Il est peut-être important de mentionner qu’à ce stade, les modèles obtenus par la fonction de compilation sont les modèles source (et non le modèle d’instance).
Les instances DOM sont souvent simplement le résultat d’un modèle source rendu dans le 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 dans le DOM, la phase de liaison commence.
Dans cette phase, Angular appelle le controller
, pre-link
, itère les enfants et appelle post-link
sur toutes les directives, comme ceci:
Les différentes fonctions directives sont exécutées depuis deux autres fonctions angulars appelées $comstack
(où la $comstack
la directive est exécutée) et une fonction interne appelée nodeLinkFn
(où le controller
la directive, preLink
et postLink
sont exécutés). Diverses choses se produisent dans la fonction angular avant et après l’appel des fonctions de la directive. Peut-être plus particulièrement la récursivité de l’enfant. L’illustration simplifiée suivante montre les étapes clés des phases de compilation et de liaison:
Pour illustrer ces étapes, utilisons le balisage HTML suivant:
Inner content
Avec la directive suivante:
myApp.directive( 'myElement', function() { return { ressortingct: 'EA', transclude: true, template: '{{label}}' } });
L’API de comstack
ressemble à ceci:
comstack: function comstack( tElement, tAtsortingbutes ) { ... }
Les parameters sont souvent préfixés par t
pour indiquer que les éléments et les atsortingbuts fournis sont ceux du modèle source, plutôt que ceux de l’instance.
Avant l’appel à comstack
contenu exclu (le cas échéant) est supprimé et le modèle est appliqué au balisage. Ainsi, l’élément fourni à la fonction de comstack
ressemblera à ceci:
"{{label}}"
Notez que le contenu exclu n’est pas réinséré à ce stade.
Suite à l’appel à la
Dans notre cas, trois instances du modèle source ci-dessus seront créées (par ng-repeat
). Ainsi, la séquence suivante s’exécutera trois fois, une fois par instance.
L’API du controller
implique:
controller: function( $scope, $element, $attrs, $transclude ) { ... }
En entrant dans la phase de liaison, la fonction de lien renvoyée via $comstack
est maintenant fournie avec une scope.
Tout d’abord, la fonction de lien crée une étendue enfant ( scope: true
) ou une scope isolée ( scope: {...}
) si nécessaire.
Le contrôleur est alors exécuté, fourni avec la scope de l’élément d’instance.
L’API de pre-link
ressemble à ceci:
function preLink( scope, element, atsortingbutes, controller ) { ... }
Pratiquement rien ne se passe entre l’appel à la directive .controller
et la fonction .preLink
. Angular recommande toujours comment chacun doit être utilisé.
Après l’appel de .preLink
, la fonction de liaison va parcourir chaque élément enfant – en appelant la fonction de lien correcte et en lui attachant l’étendue actuelle (qui sert d’étendue parent pour les éléments enfants).
L’API post-link
est similaire à celle de la fonction de pre-link
:
function postLink( scope, element, atsortingbutes, controller ) { ... }
Cela vaut peut-être la peine de noter qu’une fois la fonction
Cela signifie que, au moment où .postLink
est appelé, les enfants sont «en direct» et prêts. Ceci comprend:
Le modèle à ce stade ressemblera donc à ceci:
"{{label}}" Inner content
Si l’on doit utiliser les quatre fonctions, la directive suivra cette forme:
myApp.directive( 'myDirective', function () { return { ressortingct: 'EA', controller: function( $scope, $element, $attrs, $transclude ) { // Controller code goes here. }, comstack: function comstack( tElement, tAtsortingbutes, transcludeFn ) { // Comstack code goes here. return { pre: function preLink( scope, element, atsortingbutes, controller, transcludeFn ) { // Pre-link code goes here }, post: function postLink( scope, element, atsortingbutes, controller, transcludeFn ) { // Post-link code goes here } }; } }; });
Notez que la compilation retourne un object contenant à la fois les fonctions pré-lien et post-lien; Dans le jargon angular, nous disons que la fonction de compilation retourne une fonction de modèle .
Si le pre-link
n’est pas nécessaire, la fonction de compilation peut simplement renvoyer la fonction post-lien au lieu d’un object de définition, comme ceci:
myApp.directive( 'myDirective', function () { return { ressortingct: 'EA', controller: function( $scope, $element, $attrs, $transclude ) { // Controller code goes here. }, comstack: function comstack( tElement, tAtsortingbutes, transcludeFn ) { // Comstack code goes here. return function postLink( scope, element, atsortingbutes, controller, transcludeFn ) { // Post-link code goes here }; } }; });
Parfois, on souhaite append une méthode de comstack
, après la définition de la méthode (post) de link
. Pour cela, on peut utiliser:
myApp.directive( 'myDirective', function () { return { ressortingct: 'EA', controller: function( $scope, $element, $attrs, $transclude ) { // Controller code goes here. }, comstack: function comstack( tElement, tAtsortingbutes, transcludeFn ) { // Comstack code goes here. return this.link; }, link: function( scope, element, atsortingbutes, controller, transcludeFn ) { // Post-link code goes here } }; });
Si aucune fonction de compilation n’est nécessaire, on peut ignorer complètement sa déclaration et fournir la fonction post-link sous la propriété link
de l’object de configuration de la directive:
myApp.directive( 'myDirective', function () { return { ressortingct: 'EA', controller: function( $scope, $element, $attrs, $transclude ) { // Controller code goes here. }, link: function postLink( scope, element, atsortingbutes, controller, transcludeFn ) { // Post-link code goes here }, }; });
Dans l’un des exemples ci-dessus, on peut simplement supprimer la fonction du controller
si cela n’est pas nécessaire. Ainsi, par exemple, si seule la post-link
est nécessaire, on peut utiliser:
myApp.directive( 'myDirective', function () { return { ressortingct: 'EA', link: function postLink( scope, element, atsortingbutes, controller, transcludeFn ) { // Post-link code goes here }, }; });
Le fait que Angular autorise la manipulation DOM signifie que le balisage d’entrée dans le processus de compilation diffère parfois de la sortie. En particulier, certaines balises d’entrée peuvent être clonées plusieurs fois (comme avec ng-repeat
) avant d’être rendues dans le DOM.
La terminologie angular est un peu incohérente, mais elle distingue encore deux types de balises:
Le balisage suivant montre ceci:
{{i}}
Le HTML source définit
{{i}}
qui sert de modèle de source.
Mais comme il est encapsulé 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 scope concernée.
La fonction de comstack
chaque directive est appelée une seule fois, lorsque les bootstrap angulars.
Officiellement, c’est l’endroit où effectuer des manipulations de modèles (sources) qui n’impliquent ni scope ni liaison de données.
Principalement, cela est fait à des fins d’optimisation; considérez le balisage suivant:
La directive
rendra un ensemble particulier de balisage DOM. Nous pouvons donc soit:
ng-repeat
à dupliquer le modèle source (
), puis modifiez le balisage de chaque modèle d’instance (en dehors de la fonction de comstack
). comstack
), puis autorisez ng-repeat
à le dupliquer. S’il y a 1000 éléments dans la collection raws
, la dernière option peut être plus rapide que la précédente.
Lorsque la post-link
est appelée, toutes les étapes précédentes ont eu lieu – liaison, transclusion, etc.
Ceci est typiquement un endroit pour manipuler davantage le DOM rendu.
La fonction de controller
chaque directive est appelée chaque fois qu’un nouvel élément associé est instancié.
Officiellement, la fonction de controller
est celle où:
Encore une fois, il est important de se rappeler que si la directive implique une étendue isolée, les propriétés qui en héritent ne sont pas encore disponibles.
La fonction de pre-link
chaque directive est appelée chaque fois qu’un nouvel élément associé est instancié.
Comme vu précédemment dans la section d’ordre de compilation, pre-link
fonctions de pre-link
sont appelées parent-alors-enfant, alors que les post-link
sont appelées child-then-parent
.
La fonction de 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 auprès du contrôleur parent, mais que l’enregistrement doit être de type parent-then-child
( ngModelController
fait les choses de cette façon).