Votre quête pour cet épisode sur Angular : créer une Vue qui charge une liste de boutons, dynamiquement. Chacun des boutons va charger un component dynamiquement.
Les outils nécessaires
Pour mener à bien cette quête, nous allons avoir besoin des outils suivant :
- Création et utilisation d’une directive
- Utilisation du ComponentFactoryResolver
- Récupération du VIewContainerRef
- Utilisation d’un ng-for
- Utilisation du ng-template
- Création de Component
- Création d’une interface
Création de la directive
Commençons par la création de la directive.
Pour déposer nos futurs composants dynamiques, nous devons récupérer le conteneur de la Vue de cette directive.
Ainsi, nous saurons où créer et déposer nos composants.
Améliorons la directive, côté TypeScript, avec l’injection du ViewContainerRef :
Création du Composant parent
Pour gérer l’affichage des boutons, nous allons créer un composant parent.
Dans la vue (le template), nous allons avoir l’itération sur le tableau des données, créé côté TypeScript.
1. Génération du composant parent
2. Mise à jour de la vue Template, avec le ng-for
Pour gérer un affichage dynamique d’une liste de boutons, nous allons utiliser le ng-for.
Allons ensemble dans la Vue (le Html), et créons un bouton pour chaque élément du tableau : myDroides.
(le tableau myDroides va être créé dans la prochaine étape)
3. Création du tableau des Droides
Vu que nous avons besoin d’un tableau de Droides, nous allons le créer, du côté TypeScript.
Or, le model de classe Droide n’existe pas. Commençons par là.
Création de la classe Droide
Chaque Droide a un nom (attribut name) qui le représente. Et on va s’arrêter là pour l’instant.
(appliquons le principe du PPPP : le Plus Petit Pas Possible).
Ajout du nom dans la classe :
Création du tableau de Droide, réellement
Nous allons pouvoir enfin créer notre tableau de Droides, côté TypeScript.
Mettons à jour notre component :
Obtenir un lieu où les composants dynamiques vont être créés
Au début du tutorial Angular, nous avons créé une Directive. Cette directive va nous servir comme conteneur.
Ce conteneur va charger dynamiquement un composant, quand un clic sur un bouton sera effectué.
Or, nous ne souhaitons pas générer de html supplémentaire pour cette directive.
Donc, nous allons utiliser le ng-template.
Mettons à jour notre template html, avec le ng-template
Nous allons donc ajouter un appel à la directive landingZona. Pour ça, nous allons l’appeler par son selector appLandingZona.
Voilà tout est prêt pour le chargement de nos composants dynamiques.
Vraiment ?
Ajout du service de chargement des Droides
Actuellement, rien ne se charge sur notre page. Normal, vous allez me dire : nous n’avons aucune donnée, juste un tableau vide, dans notre composant.
Nous allons créer un service dédié pour le chargement des Droides, et puis, nous l’injecterons dans notre Component.
1. Création du Service
Exécutons la commande suivante :
2. Création d’une méthode de renvoie des Droides
Cette méthode va renvoyer un tableau de Droide.
(Dans l’intérêt de ce tutorial, nous n’allons pas gérer l’appel à une API, nous simulerons avec un tableau créé et renseigné en dur dans le Service).
Note : pensez à bien ajouter le service dans la partie providers de AppModule.
3. Injection du service et récupération des droides dans notre composant
Maintenant, et après avoir ajouté notre service dans le providers du AppModule, nous allons pouvoir l’injecter dans notre composant, et récupérer les droides.
Mettons à jour notre composant :
Nous avons enfin nos boutons qui s’affichent !
Passons à la deuxième étape : le chargement dynamique de nos composants, au clic sur chaque bouton !
Chargement dynamique des composants
Pour arriver à charger dynamiquement nos composants, quand on click sur chacun de nos boutons, nous devons mettre en place un système qui va nous faciliter la donne :
- Création d’une interface commune pour tous les composants à charger dynamiquement
- Création d’un ou deux composants implémentant cette interface
- Amélioration de notre classe Droide pour référencer le Composant lié à afficher
- Gestion du click et du chargement dynamique
1. Création de l’interface commune
Appelons-la ComposantDynamic, en lançant la commande suivante :
Ajoutons-lui la possibilité d’avoir des données en entrée, pour les afficher.
2. Passons à la création d’un ou de deux composants avec cette interface
Ici, nous allons en traiter un, vous aurez la procédure pour le second.
Générez un composant avec la commande :
Puis, implémentez l’interface ComposantDynamic
Créez-en un deuxième sur le même principe.
Point important : déclarations et entryComponents
Pour que tout le reste fonctionne, vous allez devoir OBLIGATOIREMENT déclarer vos deux composants à charger dynamiquement dans :
- Le tableau de declarations du module
- Le tableau des entryComponents, qui sert pour le chargement dynamique
3. Amélioration de notre classe Droide
Pour charger au clic un Composant dynamiquement, nous allons attacher chaque Droide à un Composant.
(bon ok, c’est pas super propre du point de vue architecture. Gardez le principe, et améliorez-le par la suite )
Voici l’amélioration de la classe :
Remarquez ici l’appel à une variable de type : Type<ComposantDynamic> qui permet d’avoir tout composant qui implémente l’interface que nous avons construit tout à l’heure.
Profitons pour améliorer la méthode getAll de la classe DroideService. Maintenant, nous devons créer des Droides, avec précision pour chaque Droide du composant lié (celui qui sera chargé dynamiquement).
Et voilà, nous sommes prêts à gérer le clic sur chaque bouton !
4. Gestion du clic et du chargement dynamique d’un component Angular
Gérons d’abord le clic
Commençons par mettre à jour notre template et notre component list-buttons-component.ts. Nous devons gérer le clic sur chaque bouton.
Nous le ferons via une méthode : loadOneComponent.
Le but de cette méthode, pour l’instant, c’est de récupérer le droide correspondant au bouton cliqué.
Nous devons d’abord mettre à jour notre template (dans le fichier list-buttons-component.ts) :
Puis, nous mettons à jour le composant lié :
Ca fonctionne, dans la console, nous avons bien le nom qui s’affiche
Puis gérons le chargement dynamic du Component lié au Droide
Ici, nous allons récupérer notre directive, pour profiter de l’accès au ViewContainerRef. Cela va nous être utile pour charger le composant créé dynamiquement, à cet endroit.
Notons ici le static à true, qui permet de récupérer la directive, avant chargement complet sur la page.
Passons au constructeur, où nous avons besoin d’injecter le chargeur et créateur de composant, j’ai bien nommé, le ComponentFactoryResolver ! C’est grâce à lui que nous pourrons créer un composant dynamiquement.
Puis, nous allons respecter les étapes suivantes au clic sur le bouton :
- Création d’une factory dédiée pour construire notre composant
- Récupération et mise à vide du Container de la directive
- Création du composant (réellement) grâce au composantFactory et au viewContainerRef de la Directive
Nous avons maintenant un composant qui charge dynamiquement des composants Angular !