DOM manipulation avec Angular Renderer2

ng-dom-namipulation

Comment manipuler le DOM avec Angular? Sais-tu utiliser le Renderer2 d’Angular pour modifier et manipuler les éléments du DOM? Trop souvent je vois des erreurs avec des appels fait avec document.querySelector() ou autres fonctions hérité de l’objet document ou window du navigateur. Dans cet article, je te montre la bonne manière de faire pour accéder ou modifier les éléments du DOM avec une application Angular.

Mais alors pourquoi ne faut-il pas utiliser l’objet natif document hérité du navigateur??

Pourtant l’utilisation de méthodes traditionnelles pour accéder au DOM fonctionne mais pourquoi donc ne doit-on pas les utilisées??

Ne pas utiliser les méthodes Native Javascript pour manipuler le DOM

Lors de l’utilisation de méthode classique Javascript pour l’accès au DOM de ton application Angular, tu augmentes les risques d’attaque XSS en créant des points d’entrée qui permettons à des hackers de lancer des attaques XSS qui pour rappel, sont un type de faille de sécurité des sites web permettant d’injecter du contenu dans une page.

Voir Wikipédia pour plus d’infos: https://fr.wikipedia.org/wiki/Cross-site_scripting

Un autre problème peut apparaitre lors de l’utilisation de l’application dans des environnements qui peuvent être rendus sur diverses plates-formes et qui n’ont pas d’accès DOM direct, comme les serveurs, les travailleurs Web ou les mobiles natifs.

Voilà pourquoi il ne faut jamais utiliser les méthodes Javascript Natives pour accéder ou manipuler le DOM d’une application Angular.

Manipuler le DOM avec Angular

Heureusement le framework Angular est tellement bien fait et complet, que même la manipulation des éléments du DOM à été pensé et incorporée au framework.

Ainsi l’utilisation de l’objet document est vraiment à proscrire d’autant plus que le framework nous met à disposition un super outil spécialement fait pour la manipulation du DOM, c’est le Renderer2 de Angular.

Lien vers la doc Angular Renderer2: https://angular.io/api/core/Renderer2

Le service Angular Renerer2

Le Renderer2 de Angular est un fabuleux outil d’abstraction pour manipuler les éléments de rendu de l’interface utilisateur de ton application au moment de l’exécution, sans avoir besoin d’accéder directement au DOM par les méthodes classiques.

En utilisant la classe Renderer2, tu peux ajouter et supprimer des classes CSS, modifier des styles et des attributs HTML, ajouter ou supprimer un élément enfant dans un élément parent, ajouter un commentaire HTML à n’importe quel élément parent du DOM, ajouter des EventsListeners et bien plus encore.

Je vais te monter avec un petit exemple comment utiliser la Class Renderer2 de Angular pour manipuler le DOM et concevoir un système « d’accordéon » pour afficher du contenu.

C’est parti!

Utilisation du Renderer2 de Angular

Pour utiliser le Renderer2, il faut en premier l’importer dans le constructeur du Component qui va en faire l’utilisation. Ceci ce fait simplement ainsi:

import { Component, Renderer2 } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {

  constructor(
    private _renderer: Renderer2
  ) {}

}

Maintenant tu pourras utiliser le Renderer dans les méthodes de ta Class pour manipuler le DOM. Mais avant cela il faut d’abord récupérer des éléments pour pouvoir les modifier. Voici comment faire.

Angular Renderer avec @ViewChildren()

Je ne sais pas si tu connais ce décorateur Angular, il permet de récupérer les éléments du DOM en consultant les enfants du Component. Ce décorateur va nous retourner les éléments du DOM que nous voulons manipuler pour concevoir notre système d’accordéon.

Lien vers la doc Angular: https://angular.io/api/core/ViewChildren

Voici comment il s’utilise:

import { Component, Renderer2, ViewChildren, QueryList, ElementRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {
  @ViewChildren('accordeon') accordeons: QueryList<ElementRef<HTMLElement>>;

  constructor(
    private _renderer: Renderer2
  ) {}

}

Ce décorateur va regarder dans mon DOM tous les éléments marqués par une référence « accordeon » et me retournera un tableau avec les résultats de ce qui aura été trouvé. C’est un peu comme un « document.querySelectorAll() » mais à la façon Angular.

La définition de la propriété et du type est suffisamment claire je pense. On définit une propriété « accordeons » qui nous retourne une liste (QueryList) d’élément référencé dans le DOM (ElementRef) avec le type précis de ces éléments (HTMLElement).

La propriété « accordeons » contient donc un tableau de tous les éléments de notre template avec la référence « accordeon« . Avec ceci, on va pouvoir travailler et modifier ces éléments avec le Renderer de Angular.

Maintenant il ne faut plus de concevoir la structure HTML de nos accordéons et de référencer chaque élément que l’on veut modifier avec Angular. Voici un exemple de HTML simpliste:


<div class="accordeons">
  <div>
    <h2 (click)="toggle($event)">item 1</h2>
    <div #accordeon class="hidden">
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Vel, reiciendis enim magnam iusto aut architecto sint hic natus? Sunt velit ab assumenda, neque et accusantium quisquam ipsum nobis eos exercitationem.
      </p>
    </div>
  </div>

  <div>
    <h2 (click)="toggle($event)">item 2</h2>
    <div #accordeon class="hidden">
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Vel, reiciendis enim magnam iusto aut architecto sint hic natus? Sunt velit ab assumenda, neque et accusantium quisquam ipsum nobis eos exercitationem.
      </p>
    </div>
  </div>

  <div>
    <h2 (click)="toggle($event)">item 3</h2>
    <div #accordeon class="hidden">
       <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Vel, reiciendis enim magnam iusto aut architecto sint hic natus? Sunt velit ab assumenda, neque et accusantium quisquam ipsum nobis eos exercitationem.
      </p>
    </div>
  </div>

  <div>
    <h2 (click)="toggle($event)">item 4</h2>
    <div #accordeon class="hidden">
       <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Vel, reiciendis enim magnam iusto aut architecto sint hic natus? Sunt velit ab assumenda, neque et accusantium quisquam ipsum nobis eos exercitationem.
      </p>
    </div>
  </div>
</div>

Tu remarques que j’ai ajouté la référence #accordeon sur certains des éléments de mon HTML. Ce sont ces références qui seront analysées par le décorateur @ViewChildren().

J’ai aussi ajouter un évènement de type « click » pour déclencher l’ouverture et fermeture de chaque section de l’accordéon.

Les animations sont uniquement créer avec du CSS pour alléger le traitement et gagner et fluidité:

.accordeons > div {
  height: 100%;
  max-height: 9999px;
  overflow: hidden;
  border: solid 1px;
  margin-top: -1px;
  padding: 0 1rem;
  box-sizing: content-box;
}

h2 {
  cursor: pointer;
}

.hidden {
  max-height: 0px!important;
}

On utilisera donc le Renderer de Angular seulement pour ajouter et retirer des Class aux éléments HTML.

Manipuler les Classes avec Renderer 2

Maintenant, il nous reste plus qu’a créer une méthode pour récupérer l’event click et modifier les classes des éléments HTML du DOM.

  toggle($event) {
    // close all open items using renderer
    this.accordeons.forEach((acc) => {
      this._renderer.addClass(acc.nativeElement, 'hidden');
    })
    // get current target
    const currentTarget = $event.target;
    // get next html element using renderer
    const currentAccordeon = this._renderer.nextSibling(currentTarget);
    // remove class using renderer
    this._renderer.removeClass(currentAccordeon, 'hidden');
  }

Étape 1:

En premier on ferme tous les accordéons en leurs ajoutant la class « hidden ».

Étape 2:

Ensuite on identifie l’élément sur lequel on à cliqué pour récupérer son élément voisin (frère) qui suit avec la méthode « nextSibling() » du Renderer2 de Angular.

Étape 3:

Et finalement on lui retire la class « hidden » pour que l’affichage fonctionne.

Aussi simple que cela!!

J’ai créé un petit projet sur StackBlitz où tu pourras voir l’exemple complet et t’en inspirer pour concevoir ton propre système d’accordéon.

Lien vers la démo:
https://stackblitz.com/edit/angular-accordeons

Conclusion

Donc garde bien tout ceci en tête quand tu travailes avec le DOM d’une application Angular. Il ne faut jamais utiliser les méthodes native Javascript pour modifier les éléments de l’interface utilisateur.

Toujours préférer l’utilisation des outils intégrer au framework utilisé avant de faire des bêtises et aller à l’encontre des bonnes pratiques préconisées.

Avec Angular, l’outil qu’il faut utiliser c’est le service Renderer2 qui permet d’effectuer ces manipulations. Chaque fois que tu dois effectuer des opérations avec le DOM, utilise cet utilitaire spécialement prévu pour.

Je te mettrai dans de prochains articles plus d’info sur l’utilisation du Renderer2 et la manipulation des éléments du DOM.

En attendant, je te laisse consulter les autres articles traitant du même sujet dans la section Angular.

Tu as besoin de support pour ton projet?
Je t’invite à te rendre sur le lien suivant pour définir ensemble une solution de support qui te convienne.

Demande ta version numérique gratuite de mon livre Javascript Array Methods

One thought on “DOM manipulation avec Angular Renderer2

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *