Appearance
Utiliser le Contexte pour propager des données dans Angular
Imaginez que vous ayez besoin de partager des informations entre un composant parent et plusieurs composants enfants. La méthode traditionnelle consisterait à passer ces données via des input()
à chaque niveau, ce qui peut devenir fastidieux et difficile à maintenir.
Le Problème
Prenons un exemple concret : un système d'onglets où chaque onglet doit savoir :
- Quel onglet est actuellement actif
- Comment changer l'onglet actif
Sans contexte, vous devriez faire quelque chose comme ceci :
ts
@Component({
template: `
<app-tabs-container [activeTab]="activeTab" (tabChange)="onTabChange($event)">
<app-tab [activeTab]="activeTab" (tabChange)="onTabChange($event)" [id]="0">
Contenu 1
</app-tab>
<app-tab [activeTab]="activeTab" (tabChange)="onTabChange($event)" [id]="1">
Contenu 2
</app-tab>
</app-tabs-container>
`
})
PROBLÈME
Cette approche crée beaucoup de code répétitif et rend la maintenance plus difficile. Chaque composant doit explicitement recevoir et transmettre les mêmes propriétés.
La Solution avec le Contexte
Au lieu de cela, nous pouvons utiliser un contexte pour partager ces informations automatiquement avec tous les composants enfants. Voici comment :
ts
import { InjectionToken } from '@angular/core';
export interface TabsContext {
activeTabId: number;
selectTab: (id: number) => void;
}
export const TABS_CONTEXT = new InjectionToken<TabsContext>('TABS_CONTEXT');
ts
@Component({
selector: 'app-tabs-container',
standalone: true,
template: `
<div class="tabs-container">
<ng-content></ng-content>
</div>
`,
providers: [
{
provide: TABS_CONTEXT,
useExisting: TabsContainerComponent
}
]
})
export class TabsContainerComponent implements TabsContext {
activeTab = input.required<number>();
tabChange = output<number>();
}
ts
import { input, inject, Component, computed } from '@angular/core';
@Component({
selector: 'app-tab',
standalone: true,
template: `
@if (isActive()) {
<div class="tab-content">
<ng-content></ng-content>
</div>
}
`
})
export class TabComponent {
protected tabsContext = inject(TABS_CONTEXT);
id = input.required<number>();
isActive = computed(() => this.tabsContext.activeTabId() === this.id());
}
Utilisation
Maintenant, l'utilisation devient beaucoup plus simple et propre :
ts
@Component({
selector: 'app-user-profile',
standalone: true,
imports: [TabsContainerComponent, TabComponent],
template: `
<app-tabs-container [activeTab]="activeTab" (tabChange)="onTabChange($event)">
<app-tab [id]="0">
<h3>Informations Utilisateur</h3>
<p>Nom: {{ user.name }}</p>
</app-tab>
<app-tab [id]="1">
<h3>Paramètres</h3>
<p>Email: {{ user.email }}</p>
</app-tab>
</app-tabs-container>
`
})
```