Angular2 – UI : repensez vos modals pour des fenêtres dynamiques

Notre besoin était d’avoir une modal comme d’habitude, puis une modal dans une modal, comme d’habitude.. Mais comment afficher deux modales à la fois sur une page.

C’est en regardant Tag Manager de Google que nous nous sommes grandement inspiré de leur implémentation pour créer notre propre SheetComponent pour Angular2.

Le principe est d’ouvrir une fenêtre venant de la droite de l’écran et se déplaçant vers la gauche jusqu’à une certaine distance sans coller au bord de l’écran, puis d’insérer dans la fenêtre le composant désiré. Pour ouvrir une seconde fenêtre, on va décaler la première jusqu’au bord de l’écran, et afficher la nouvelle depuis la droite de l’écran jusqu’à une certaine distance…etc..on peut faire ça à l’infini.

Problématiques:

  • Comment créer une fenêtre dynamiquement
  • Comment créer un composant dynamiquement
  • Comment insérer le composant dans la fenêtre
  • Comment ouvrir des fenêtres à l’infini

Démo live

Tout d’abord il nous faut une liste de SheetComponent

On a trois méthodes publiques. La première addSheet permettra d’ajouter un sheet dans la liste et de créer le composant. ComponentCreated est appelé par le SheetComponent lorsqu’il aura créé le véritable composant, auquel on attache un EventEmitter et affiche la fenêtre. CloseSheet ne fait que supprimer la dernière entrée de la liste des sheets.

Le service SheetService :

On utilise jQuery pour des raisons de simplicité, mais on peut s’en passer. Quand les animations d’angular permettront d’en faire autant, il sera bon de s’en servir. Avec ce service on va gérer les animations, ouverture et fermeture des fenêtres. Les timeout nous sont utiles pour laisser le temps aux transitions de s’exécuter.

Vient ensuite le SheetListService, qui va s’occuper de créer le composant dynamiquement et de garder en mémoire la référence du SheetListComponent.

Et pour finir le SheetComponent

Pour instancier ce premier composant, on va ce servir de ng-template. Dans un de vos templates, ajoutez cette ligne

<ng-template #sheetListContainer></ng-template>

Et dans le composant du template :

sheetList: SheetListComponent;
@ViewChild('sheetListContainer', {read: ViewContainerRef}) sheetListContainer;
  • sheetList sera la référence au composant SheetListComponent
  • sheetListContainer servira comme argument de initOrGetSheetList.

La méthode initOrGetSheetList va créer notre composant via une factory et nous retourner la référence du composant créé.

On aurait pu instancier le composant dans la vue directement et récupérer sa référence via le #. Mais on ne profiterait plus du service qui garderait en mémoire sa référence pour s’en servir dans nos SheetComponent.

Maintenant dans le composant où on a initialisé les variables, on va créer une petite méthode pour instancier le SheetListComponent.

private sheetListInit() {
    this.sheetList = this.sheetListService.initOrGetSheetList(this.sheetListContainer);

    this.sheetList.onComponentCreated.subscribe(
      (params) => {
        this.componentCreated(params);
      }
    )
  }

On peut également souscrire directement à l’Output onComponentCreated du SheetListComponent, c’est un simple Subject de RxJS.

Souvenez-vous que le résultat de onComponentCreated correspondra au composant qui sera affiché dans un SheetComponent. C’est très utile si on veut récupérer des données d’un formulaire par exemple.

Pour une implémentation complète, suivez le lien et agrandissez un peu la zone de preview.

Démo live

Amusez-vous bien !

Partagez cet article