Skip to content

Comment utiliser @ContentChild sur Angular ?

@ContentChild est un décorateur Angular qui permet de récupérer une référence à un enfant de contenu d'un composant. Vous pouvez l'utiliser pour accéder à un élément HTML ou à une directive présente dans le contenu transcluded (inclus) d'un composant.

Voici un exemple de code montrant comment utiliser @ContentChild :

ts
import { Component, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <ng-content></ng-content>
  `
})
export class MyComponent {
  @ContentChild('myElement') myElement: ElementRef;

  ngAfterContentInit() {
    console.log(this.myElement);
  }
}
import { Component, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <ng-content></ng-content>
  `
})
export class MyComponent {
  @ContentChild('myElement') myElement: ElementRef;

  ngAfterContentInit() {
    console.log(this.myElement);
  }
}

Dans cet exemple, nous avons déclaré une référence de contenu appelée myElement qui référence l'élément HTML portant l'attribut #myElement. Dans la méthode ngAfterContentInit, nous pouvons accéder à l'élément en utilisant this.myElement.

Pour utiliser ce composant, nous pouvons inclure du contenu dans le template de notre composant parent, comme ceci :

html
<app-my-component>
  <div #myElement>Contenu inclus</div>
</app-my-component>
<app-my-component>
  <div #myElement>Contenu inclus</div>
</app-my-component>

En utilisant @ContentChild, vous pouvez accéder à tous les éléments et directives inclus dans le contenu transcluded de votre composant, ce qui peut être utile pour réaliser des opérations sur ces éléments ou directives.

Exemple concret

Supposons que vous avez un composant MyButton qui affiche un bouton et qui prend en entrée un titre de bouton à afficher en utilisant une propriété de liaison de données :

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

@Component({
  selector: 'app-my-button',
  template: `
    <button>{{ buttonTitle }}</button>
  `
})
export class MyButtonComponent {
  @Input() buttonTitle: string = '';
}
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-my-button',
  template: `
    <button>{{ buttonTitle }}</button>
  `
})
export class MyButtonComponent {
  @Input() buttonTitle: string = '';
}

Maintenant, supposons que vous souhaitez utiliser ce composant MyButton dans un autre composant, mais que vous souhaitiez ajouter une icône avant le titre du bouton. Vous pouvez utiliser @ContentChild pour réaliser cette opération.

Voici comment le code du composant parent pourrait ressembler :

ts
import { Component, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <app-my-button>
      <i class="material-icons" #buttonIcon>favorite</i>
      {{ buttonTitle }}
    </app-my-button>
  `
})
export class MyComponent {
  @ContentChild('buttonIcon') buttonIcon: ElementRef;

  buttonTitle = 'Mon bouton';

  ngAfterContentInit() {
    console.log(this.buttonIcon);
  }
}
import { Component, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <app-my-button>
      <i class="material-icons" #buttonIcon>favorite</i>
      {{ buttonTitle }}
    </app-my-button>
  `
})
export class MyComponent {
  @ContentChild('buttonIcon') buttonIcon: ElementRef;

  buttonTitle = 'Mon bouton';

  ngAfterContentInit() {
    console.log(this.buttonIcon);
  }
}

Dans ce code, nous avons inclus un élément i dans le contenu transcluded de app-my-button, et nous lui avons attribué l'identifiant #buttonIcon. Nous avons déclaré une référence de contenu appelée buttonIcon qui référence cet élément i.

Dans la méthode ngAfterContentInit, nous pouvons accéder à cet élément en utilisant this.buttonIcon. Vous pouvez maintenant utiliser cette référence pour réaliser des opérations sur l'élément, comme par exemple changer sa couleur en utilisant this.buttonIcon.nativeElement.style.color = 'red'.

Le template final de votre composant ressemblera à ceci :

html
<app-my-button>
  <i class="material-icons" style="color: red;">favorite</i>
  Mon bouton
</app-my-button>
<app-my-button>
  <i class="material-icons" style="color: red;">favorite</i>
  Mon bouton
</app-my-button>