
Directives Angular : simplifiez votre code
Dans le développement d’applications Web modernes, Angular s’est imposé comme l’un des frameworks incontournables grâce à sa robustesse et sa flexibilité. Bien que les développeurs utilisent souvent l’ensemble des fonctionnalités d’Angular, les directives restent souvent méconnues et sous-estimées. Pourtant, elles permettent de simplifier le code et de rendre les applications plus modulaires et plus faciles à maintenir. Dans cet article, nous allons découvrir les directives Angular et voir comment les utiliser pour améliorer la qualité de notre code.
Le constat : une sous-utilisation des directives Angular
Lors de mes interventions sur divers projets Angular, j’ai souvent constaté que les directives étaient sous-utilisées. Les développeurs privilégient généralement les composants Angular, plus faciles à comprendre et à utiliser.
Cette tendance est probablement due à la documentation officielle d’Angular, qui met l’accent sur les composants et les services dans ses chapitres introductifs. Cette approche est suffisante pour créer la majorité des applications, mais elle laisse les directives dans l’ombre.
Les directives Angular sont ainsi méconnues ou perçues comme des outils avancés. Pourtant, elles peuvent grandement simplifier les solutions techniques et améliorer la qualité du code.
Les directives Angular : qu’est-ce que c’est ?
Les directives Angular sont des éléments puissants qui permettent d’ajouter des comportements à des éléments HTML ou des composants Angular. Elles sont utilisées pour étendre les fonctionnalités du langage HTML et encapsuler des comportements réutilisables.
D’ailleurs, vous avez probablement déjà utilisé des directives sans le savoir, comme par exemple :
NgModel
qui modifie le comportement d’un élément de formulaireNgClass
etNgStyle
qui modifient dynamiquement les attributs d’un élément HTML- Ou
NgIf
,NgFor
etNgSwitch
qui modifient la structure du DOM
Quand utiliser les directives Angular ?
Pour illustrer l’intérêt des directives, reprenons l’exemple du redimensionnement automatique d’un textarea que j’ai présenté dans un précédent article.
Imaginons que nous devions ajouter cette fonctionnalité à plusieurs composants de notre application. Sans directives, nous aurions deux options :
- Créer un composant spécifique pour le redimensionnement automatique du textarea.
- Dupliquer le code de redimensionnement dans chaque composant qui en a besoin.
La première option pourrait convenir si le textarea est indépendant et réutilisable. Cependant, c’est rarement le cas car les textarea sont souvent intégrés dans des formulaires ou des composants plus complexes. La deuxième option est plus simple, mais elle entraîne des duplications de code et augmente la complexité du projet, rendant sa maintenance plus difficile.
C’est dans ce contexte que les directives Angular prennent tout leur sens. Elles permettent d’encapsuler le comportement de redimensionnement automatique du textarea dans une classe réutilisable et simple à exploiter. Cela simplifie le code des composants et étend leur comportement sans compromettre leur maintenabilité. En résumé, les directives Angular permettent de définir des comportements transversaux réutilisables dans n’importe quel composant de l’application.
Créer une directive Angular d’auto-redimensionnement pour un textarea
Générer une directive avec Angular CLI
La méthode la plus simple pour créer une directive Angular est d’utiliser Angular CLI. Voici la commande à exécuter dans le terminal :
$ npx ng generate directive shared/auto-resize <1>
CREATE src/app/shared/auto-resize.directive.spec.ts (249 bytes)
CREATE src/app/shared/auto-resize.directive.ts (180 bytes)
J’utilise npx
pour exécuter la commande Angular CLI propre au projet plutôt que la version installée globalement.
Angular CLI génère deux fichiers : un fichier directive et le fichier de test unitaire associé.
Le code source de la directive devrait ressembler au suivant :
// /src/app/directives/auto-resize.directive.ts
import { Directive } from '@angular/core';
@Directive({
selector: '[appAutoResize]',
standalone: true
})
export class AutoResizeDirective {
constructor() { }
}
Au même titre que les composants, la directive est associée à un sélecteur qui permet de l’appliquer à un élément HTML. Dans notre cas, le sélecteur est appAutoResize
.
Implémenter la logique de redimensionnement automatique
Pour implémenter la logique de redimensionnement automatique, nous allons intégrer le code présenté dans mon article précédent en l’adaptant à Angular :
// /src/app/directives/auto-resize.directive.ts
import {
Directive,
ElementRef,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
@Directive({
selector: '[appAutoResize]',
standalone: true
})
export class AutoResizeDirective implements OnInit, OnDestroy {
/** Espacement interne vertical du textarea. */
private yPadding: number = -1;
/** Hauteur d'une ligne de texte dans le textarea. */
private lineHeight: number = -1;
/** Référence vers l'élément textarea. */
private get el(): HTMLTextAreaElement {
return this.ref.nativeElement;
}
/** Références des callbacks branchés au DOM. */
private listeners: { [key: string]: (ev: Event) => any } = {};
/** Nombre de lignes minimum. */
@Input('rows-min') // <1>
public rowsMin: number = 1;
/** Nombre de lignes maximum. */
@Input('rows-max') // <1>
public rowsMax: number = 4;
constructor(
private readonly ref: ElementRef<HTMLTextAreaElement>
) {}
public ngOnInit(): void { // <2>
this.configureHeights();
// Configurer la taille de base
this.resize();
this.listeners['input'] = (_) => this.resize();
this.listeners['resize'] = () => {
this.configureHeights();
this.resize();
};
this.el.addEventListener('input', this.listeners['input']);
window.addEventListener('resize', this.listeners['resize']);
}
public ngOnDestroy(): void { // <2>
this.el.removeEventListener('input', this.listeners['input']);
window.removeEventListener('resize', this.listeners['resize']);
}
/**
* Calcule les hauteurs des lignes et du padding lorsque c'est nécessaire.
*/
private configureHeights(): void {
const clone = this.el.cloneNode() as HTMLTextAreaElement;
clone.rows = 1;
// Configurer l'élément comme invisible
clone.style.position = 'absolute';
clone.style.visibility = 'hidden';
// Supprimer les espacements verticaux parasites (sauf padding)
clone.style.border = 'none';
clone.style.height = '';
clone.style.minHeight = '';
clone.style.maxHeight = '';
if (this.el.parentNode) {
this.el.parentNode.appendChild(clone);
const height = clone.clientHeight;
clone.style.padding = '0';
this.lineHeight = clone.clientHeight;
this.yPadding = height - this.lineHeight;
}
clone.remove();
this.setHeightRange();
}
/**
* Configure l'attribut rows et la hauteur min et max du textarea.
*/
private setHeightRange() {
// Récupération des paramètres
const min = this.rowsMin;
const max = this.rowsMax;
const borderWidth = this.el.offsetHeight - this.el.clientHeight;
// Appliquer les règles
this.el.rows = min;
this.el.style.minHeight = `${borderWidth + this.yPadding + this.lineHeight * min}px`;
this.el.style.maxHeight = `${borderWidth + this.yPadding + this.lineHeight * max}px`;
}
/**
* Redimensionnement automatique du textarea.
*/
private resize() {
console.log(this);
// Calcul de la hauteur à partir du contenu courant
this.el.style.height = '';
this.el.style.height = `${this.el.offsetHeight - this.el.clientHeight + this.el.scrollHeight}px`;
}
}
Les directives Angular acceptent des données en entrée via des propriétés décorées avec @Input
. Cette approche permet de reproduire l’exploitation des datasets HTML utilisées dans le code source original.
Les directives Angular peuvent s’attacher aux événements du cycle de vie Angular comme les composants. Dans notre cas, nous utilisons les méthodes ngOnInit
et ngOnDestroy
pour initialiser et nettoyer les listeners.
L’implémentation de la directive est assez similaire à celle du code original. Nous avons simplement adapté le code pour respecter les conventions propres à Angular et pour permettre une utilisation plus modulaire.
Utilisation de la directive Angular
Maintenant que la directive est prête, nous pouvons l’utiliser dans n’importe quel composant Angular. Pour illustrer son utilisation, nous allons reproduire l’exemple du textarea redimensionnable dans le composant Angular AppComponent
.
Modification du template du composant
// /src/app/app.component.html
// ...
.content p {
margin-top: 1.5rem;
}
+
+ .mt-4 {
+ margin-top: 2rem;
+ }
+
+ .mt-3 {
+ margin-top: 1rem;
+ }
+ textarea.field {
+ width: 100%;
+ resize: none;
+ }
}
</style>
<main class="main">
<div class="content">
+ <h1>Redimensionnement automatique du textarea</h1>
+ <div class="mt-4">
+ <textarea class="field" appAutoResize></textarea> // <1>
+ </div>
+ <div class="mt-3">
+ <textarea class="field" appAutoResize [rows-min]="2" [rows-max]="10"></textarea> // <1>
+ </div>
</div>
</main>
// ...
Nous appliquons notre directive d’auto-redimensionnement en utilisant le sélecteur appAutoResize
sur les deux textarea.
Dans cet exemple, nous avons ajouté deux textarea redimensionnables dans le template du composant AppComponent
. Le premier textarea utilise les valeurs par défaut pour le nombre de lignes minimum et maximum, tandis que le second définit des valeurs personnalisées.
Déclaration de la directive dans le composant
Pour que la directive soit reconnue par Angular, nous devons l’ajouter dans le tableau d’import du composant. Voici comment cela se présente dans le fichier du composant AppComponent
:
// /src/app/app.component.ts
// ...
import { RouterOutlet } from '@angular/router';
+import { AutoResizeDirective } from './shared/auto-resize.directive';
+
@Component({
selector: 'app-root',
standalone: true,
- imports: [RouterOutlet],
+ imports: [
+ RouterOutlet,
+ AutoResizeDirective,
+ ],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
// ...
Comme vous pouvez le voir, l’utilisation de la directive dans un composant Angular est très simple et flexible. Elle permet d’ajouter des fonctionnalités supplémentaires à n’importe quel élément HTML sans compromettre la structure du composant.
Conclusion
Dans cet article, nous avons illustré l’exploitation des directives Angular à travers un exemple concret de redimensionnement automatique d’un textarea. Nous avons vu comment créer une directive avec Angular CLI et implémenter la logique de redimensionnement automatique.
Cette approche démontre l’intérêt et la simplicité des directives dans le développement d’applications Web Angular. Elles permettent d’ajouter des comportements réutilisables et transversaux, tout en améliorant la maintenabilité et la qualité du code.
En conclusion, les directives Angular sont des outils puissants qui méritent d’être mieux connus et exploités. Je vous encourage à explorer d’autres cas d’utilisation des directives pour tirer pleinement parti de leur potentiel.