Skip to content

Vous souhaitez recevoir de l'aide sur ce sujet ? rejoignez la communauté Angular.fr sur Discord.

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>
  `
})
```