Injection de dépendance > Naviguer dans l'arborescence des composants avec DI

Références

L'actualité

Librairie

L'information

Naviguer dans l'arborescence des composants avec DI

Les composants de l'application ont souvent besoin de partager des informations. Vous pouvez souvent utiliser des techniques faiblement couplées pour le partage d'informations, telles que la liaison de données et le partage de services, mais il est parfois judicieux qu'un composant ait une référence directe à un autre composant. Par exemple, vous avez besoin d'une référence directe pour accéder à des valeurs ou à des méthodes d'appel sur ce composant.

Obtenir une référence de composant est un peu délicat en Angular. Les composants Angular eux-mêmes n'ont pas d'arborescence que vous pouvez inspecter ou naviguer par programme. La relation parent-enfant est indirecte et établie à travers les objets de vue des composants.

Chaque composant a une vue d'hôte et peut avoir d'autres vues intégrées. Une vue intégrée dans le composant A est la vue hôte du composant B, qui peut à son tour comporter une vue intégrée. Cela signifie qu'il existe une hiérarchie de vues pour chaque composant, la vue hôte de ce composant étant la racine.

Il existe une API pour naviguer dans la hiérarchie des vues. Consultez Query, QueryList, ViewChildren et ContentChildren dans l'API de référence .

Il n'y a pas d'API publique pour l'acquisition d'une référence parente. Cependant, étant donné que chaque instance de composant est ajoutée au conteneur d'un injecteur, vous pouvez utiliser l'injection de dépendance Angular pour atteindre un composant parent.

Cette section décrit certaines techniques pour le faire.

Trouver un composant parent de type connu

Vous utilisez l'injection de classe standard pour acquérir un composant parent dont vous connaissez le type.

Dans l'exemple suivant, le parent AlexComponent a plusieurs enfants dont CathyComponent :
AlexComponent v.1

Cathy indique si elle a ou non accès à Alex après avoir injecté un produit AlexComponent dans son constructeur:
CathyComponent

Notez que même si le qualificatif @Optional est là pour la sécurité.

Impossible de trouver un parent par sa classe de base

Que faire si vous ne connaissez pas la classe de composant parent concrète ?

Un composant réutilisable peut être un enfant de plusieurs composants. Imaginez un composant permettant de rendre les dernières nouvelles concernant un instrument financier. Pour des raisons commerciales, cette nouvelle composante passe fréquemment des appels fréquents dans son instrument parent en modifiant les flux de données du marché.

L'application définit probablement plus d'une douzaine de composants d'instruments financiers. Si vous êtes chanceux, ils implémentent tous la même classe de base que l'API que vous comprenez NewsComponent.

Il serait préférable de rechercher des composants qui implémentent une interface. Ce n'est pas possible car les interfaces TypeScript disparaissent du code JavaScript transpilé, qui ne prend pas en charge les interfaces. Il n'y a pas d'artefact à rechercher.

Ce n'est pas nécessairement un bon design. Cet exemple examine si un composant peut injecter son parent via la classe de base du parent .

L'échantillon CraigComponent explore cette question. En regardant en arrière, vous voyez que le composant Alex s'étend ( hérite ) d'une classe nommée Base.

Signature de la classe Alex

Le CraigComponent tente d'injecter dans Base son alex paramètre constructeur et indique s'il a réussi.

CraigComponent

Malheureusement, ça ne marche pas. Vous ne pouvez pas injecter un parent par sa classe de base.

Trouver un parent par son interface de classe

Vous pouvez trouver un composant parent avec une interface de classe. Le parent doit coopérer en se fournissant un alias lui-même sous le nom d'un jeton d'interface de classe.

Rappelez-vous que Angular ajoute toujours une instance de composant à son propre injecteur. c'est pourquoi vous pourriez injecter plutôt Alex à Cathy.

Ecrivez un fournisseur d'alias un littéral provide d'objet avec une useExisting définition qui crée un autre moyen d'injecter la même instance de composant et d'ajouter ce fournisseur au tableau providers des métadonnées du fichier @Component() de AlexComponent

Fournisseurs AlexComponent

Parent est le jeton d'interface de classe du fournisseur. Le forwardRef brise la référence circulaire que vous venez de créer en ayant la référence AlexComponent à lui-même.

Carol, le troisième des composants enfants d'Alex, injecte le paramètre parent parent dans son paramètre, de la même manière que vous l'avez fait auparavant.

classe CarolComponent

Voici Alex et sa famille en action.



Trouver un parent dans une arborescence avec @SkipSelf()

Imaginez une branche d'une hiérarchie de composants: Alice -> Barry -> Carol. Les deux Alice et Barry implémentent l'interface de classe "mère".

Barry est le problème. Il doit atteindre son parent, Alice , et aussi être un parent pour Carol. Cela signifie qu'il doit à la fois injecter l'interface Parent de classe pour obtenir Alice et fournir un moyen Parent de satisfaire Carol.

Voici Barry.

BarryComponent

Le tableau providers de Barry ressemble à celui d'Alex. Si vous continuez à écrire des fournisseurs d'alias de cette manière, vous devez créer une fonction d'assistance.

Pour l'instant, concentrez-vous sur le constructeur de Barry.

Le constructeur de Barry

Le constructeur de Carol

Il est identique au constructeur de Carol à l 'exception du décorateur supplémentaire @SkipSelf

@SkipSelf est essentiel pour deux raisons :
  • Il relate l'injecteur pour commencer la recherche d'une dépendance Parent dans un élément ci-dessus lui-même, qui est ce que signifie père.
  • Angular génère une erreur de dépendance cyclique si vous omettez le décorateur @SkipSelf

Voici Alice, Barry et sa famille en action.




Interface de classe parent

Vous avez appris précédemment qu'une interface de classe est une classe abstraite utilisée comme interface plutôt que comme classe de base.

L'exemple définit une interface de classe Parent.

L'interface de classe Parent définit une propriété name avec une déclaration de type mais aucune implémentation. La propriété name est le seul membre d'un composant parent qu'un composant enfant peut appeler. Une interface aussi étroite permet de découpler la classe de composants enfants de ses composants parents.

Un composant qui pourrait servir de parent devrait implémenter l'interface de classe comme le fait le Component Alice.

Signature de la classe AliceComponent

Cela ajoute de la clarté au code. Mais ce n'est pas techniquement nécessaire. Bien que AlexComponent possède une propriété name, comme l'exige sa classe Base, sa signature de classe ne le mentionne pas Parent.

Signature de classe AlexComponent

AlexComponent devrait mettre Parent en oeuvre comme une question de style approprié. Dans cet exemple, il ne suffit pas de démontrer que le code sera compilé et exécuté sans l'interface.

Fonction d'assistance provideParent()

écrire des variantes du même fournisseur d'alias parent vieillit rapidement, en particulier cette affreuse bouchée avec un forwardRef.

parent-finder.component.ts

Vous pouvez extraire cette logique dans une fonction d'assistance comme suit.

parent-finder.component.ts

Vous pouvez maintenant ajouter un fournisseur parent plus simple et plus significatif à vos composants.

parent-finder.component.ts

Tu peux faire mieux. La version actuelle de la fonction d'assistance ne peut aliaser que l'interface Parent de classe. L'application peut avoir divers types de parents, chacun avec son propre jeton d'interface de classe.

Voici une version révisée qui utilise par défaut parent mais accepte également un second paramètre facultatif pour une interface de classe parente différente.

parent-finder.component.ts

Et voici comment vous pouvez l'utiliser avec un type de parent différent.

parent-finder.component.ts