Angular est un framework basé sur les custom components, donc on n'a pas accès à l'élément racine depuis notre template.
Ça peut être très frustrant quand on a l'habitude des frameworks concurents, comme React ou VueJS. Pas la peine de se prendre la tête non-plus, c'est tout à fait possible de définir des attributs sur notre élément racine, par contre ça se fera depuis notre code JavaScript. J'ai noté trois solutions, je vous les présente de la plus simple à la plus compliquée.
Lorsque l'on définit un nouveau composant, on utilise le décorateur @Component()
. Celui-ci marque une classe
comme étant "un composant angular" et nous permet de définir des méta-données de configuration.
La première solution est donc d'utiliser la méta-donnée host
du décorateur de composant. Cette
propriété nous permet d'ajouter des attributs et des événements directement sur l'élément
racine.
import { Component } from "@angular/core";
@Component({
selector: "my-component",
templateUrl: "./my-component.component.html",
styleUrls: ["./my-component.component.scss"],
host: {
class: "c-my-component c-my-component--full"
}
})
export class MyComponent {}
Le code précédent définit un composant angular my-component
que vous pouvez utiliser comme ceci :
<my-component></my-component>
Le DOM généré sera :
<my-component class="c-my-component c-my-component--full"></my-component>
Source : la documentation d'Angular.
La deuxième solution permet d'avoir une gestion un peu plus fine des classes à associer à notre composant. Il n'est
pas possible avec le décorateur de composant d'avoir de logique sur les classes à appliquer. Ainsi, on ne peut pas
appliquer la classe c-my-component--full
en fonction des attributs de notre composant angular.
Si on a ce besoin de logique, on peut alors utiliser le décorateur d'attribut @HostBinding()
:
import { Component } from '@angular/core';
@Component({
selector: "my-component",
templateUrl: "./my-component.component.html",
styleUrls: ["./my-component.component.scss"],
})
export class MyComponent {
@HostBinding("class.c-my-component") readonly rootClass = true;
@HostBinding("class.c-my-component--full") @Input() isFull: boolean = false;
}
On pourra donc utiliser l'attribut isFull
pour appliquer ou pas notre classe :
<my-component></my-component> <my-component [isFull]="true"></my-component>
Le DOM généré sera :
<my-component class="c-my-component"></my-component>
<my-component class="c-my-component c-my-component--full"></my-component>
Source : la documentation d'Angular.
Si on a beaucoup de classes possibles, la méthode précédente peut être un peu verbeuse. Un autre défaut est qu'on ne peut pas créer des noms de classes dynamiques.
Pour palier à ces problèmes, il est également possible d'utiliser le décorateur @HostBinding()
sur une méthode.
import { Component } from "@angular/core";
@Component({
selector: "my-component",
templateUrl: "./my-component.component.html",
styleUrls: ["./my-component.component.scss"]
})
export class MyComponent {
@Input() theme: string;
@HostBinding("class")
get hostClasses(): string {
let classes = ["c-my-component"];
if (this.theme) {
classes.push(`c-my-component--${this.theme}`);
}
return classes.join(" ");
}
}
On pourra alors utiliser l'attribut theme
pour appliquer des classes dynamiques :
<my-component></my-component> <my-component [theme]="dark"></my-component>
Le DOM généré sera :
<my-component class="c-my-component"></my-component>
<my-component class="c-my-component c-my-component--dark"></my-component>