Comprendre les structural directives d'angular
J’ai beaucoup utilisé les directives structurelles sans avoir pris le temps de me demander comment ça fonctionnait, cependant la “mycrosyntaxe” d’angular paraissait suffisamment puissante pour y faire un détour, initialement je me suis souvent demander ce qui était possible de faire grace aux templates angular, alors voyons comment cela fonctionne.
La surface de l’iceberg
Les directives structurelles d’angular sont les directives qui manipulent les éléments du dom, reconnaissables du fait qu’elles commencent toutes par un asterisk, comme par exemple *ngIf et *ngFor.
Pour pouvoir manipuler le dom, ces directives wrap le nœud actuel du dom dans un élément
|
|
La microsyntaxe
L’exemple précédent était simple, ici on va aller plus loins et s’intéresser à la microsyntaxe qui est un langage dédié ( ou Domain Language Specific ) et qui permet de créer le template avec tous les bindings nécessaires. Autrement dit, c’est la string donnée à votre directive.
Prenons le cas le plus répandu et clair : la directive *ngFor.
|
|
On peut identifier la microsyntaxe qui est ”let item of items; let i=index” Le parser dédié a permit de déterminer 3 elements clef :
- les mot clef “let ” étaient des attributs.
- le mot clef “of ” un binding de type @Input() nommé “ngForOf”.
- notre directive initiale “ngFor ”.
une fois les éléments identifiés, ils sont replacé dans le template.
Mais d’ou ça sort tout ça ?
Tout d’abord le mot clef “of ” est une propriété appartenant à la directive ngFor, la microsyntaxe définit les propriétés comme étant préfixés par le nom de la directive, donc of fait référence à la propriété ngForOf et contrairement aux let-** ici c’est un binding type @Input().
En suite “let ” représente un template input variable c’est à dire une variable à laquelle nous aurons accès, scopé dans le template ( donc aussi à ses enfants ), leurs valeurs viennent de la directive elle-même, mais nous allons voir ça par la suite
Contenu d’une directive structurelle
Création
Ok, avant de commencer à créer notre directive il faut savoir qu’une directive de ce type est composé d’un contexte, celui-ci est un objet contenant toutes les propriétés dont nous avons besoin ( les fameux let-i et let-item dans l’exemple du *ngFor ) ainsi qu’une propriété spéciale “$implicit” qui représente la référence de tout ce qui n’est pas assigné par une valeur dans la microsyntaxe. Avec un schema ça passe mieux ↓
Postulat :
|
|
|
|
Maintenant nous allons créer une directive nous même.
|
|
Dans un premier temps il va falloir injecter 2 ressources nécessaires au templating,
- La référence d’un template via la class TemplateRef
- La référence du conteneur pour éditer les vues, via la class ViewContainerRef
Puis nous rajoutons une propriété input représentant ce que l’on va binder à la directive
|
|
Définissons un contexte
|
|
Il ne reste plus qu’à créer la vue embarquée
|
|
Voila, seulement à ce stade , rien ne se passe, car nous disposons bien d’une balise
Manipulation du DOM
Pour créer des vues embedded, il suffit d’utiliser le templateRef et le viewContainerRef afin de créer une vues enfant basé sur un template donné. On va faire quelque chose de semblable à la directive *ngFor, tout à l’heure nous avions splité notre chaine de caractères, nous allons créer une vue pour chacune des cases du tableau obtenu.
|
|
d’abord un clear pour vider le container, puis pour chacune des entrées nous créons une vue, en donnant en guise de paramètre , le template initial , et un nouveau contexte.
il ne reste plus qu’à appeler la directive dans une vue
|
|
Et voila vous savez l’essentiel sur les directives structurelles. Maintenant les syntaxes comme ngIf=“condition else otherTemplate” deviennent clair, tout comme le fait qu’angular nous limite à une seule directive structurelle par balise, forcément il serait difficile pour 2 directives de vouloir manipuler le même DOM en simultané. Du coup la derniere question à se poser c’est :component ou directive ?
En fait je dirai que les 2 ont un role bien different, on va répondre à une demande de structuration avec les components, qui sont les briques principales de l’application et au contraire plutot répondre à un besoin de logique et de dynamisme avec les directives structurelles qui sont plus souples (intéraction facile avec l’host ou lels éléments enfants), un exemple simple serait un tableau dynamique qui peut , dans chaque case afficher différent type de donnée : texte brut, input de formulaire, boutton ..etc, le tableau en lui même sera un composant, tandis qu’on va jouer sur les template pour fournir le bon format de donnée dans les cases.
Code complet et démo sur le Stackblitz ci-dessous ↓↓
Bonus
Si vous etes habitué du pipe async d’angular vous devez parfois voir ce genre de code
|
|
Le mot clef “as” est propre à la microsyntaxe (donc utilisable au sein d’un template) et permet d’exporter une valeur vers une nouvelle variable. Via une directive vide de logique on va pouvoir réutiliser ce qui est fait ci-dessus sans être obligé d’utiliser un ngIf qui va masquer votre template si la condition n’est pas remplie. ( voir “mySecondDirective” sur le stackblitz )