Angular est-il vraiment plus compliqué que React ?

Quand on débute avec Angular, il est facile de se sentir découragé face à la multitude de concepts à assimiler. Cette complexité peut inciter à se tourner vers des frameworks comme React, qui semblent plus simples à première vue. Mais est-ce vraiment le cas ?

Abonnez-vous à notre chaîne

Pour profiter des prochaines vidéos sur Angular, abonnez-vous à la nouvelle chaîne YouTube !

Skip to content

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

Comment utiliser viewChild() dans un composant dans Angular ?

Les requêtes de vue permettent d'accéder aux éléments définis dans le template d'un composant.

Utiliser les composants avec des signaux

Depuis Angular 17.x, les signaux sont introduits en tant que réactifs comme alternative aux décorateurs @Input(), @Output(), etc.

Donc, pour utiliser input(), output(), model(), contentChild(), contentChildren(), viewChild() et viewChildren(), il est essentiel de comprendre la notion des signaux.

Lisez l'article sur les signaux pour en savoir plus.

La fonction viewChild()

viewChild() permet d'accéder à un élément unique dans le template. Voici un exemple simple :

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

@Component({
  selector: 'app-user-card',
  standalone: true,
  template: `
    <div #userInfo>
      {{ user.name }}
    </div>
    <button (click)="highlightUser()">Mettre en évidence</button>
  `
})
export class UserCardComponent {
  user: User = {
    id: 1,
    name: 'John Doe',
    username: 'johndoe',
    email: '[email protected]'
  };

  // Accès à l'élément via viewChild
  userInfoElement = viewChild<ElementRef<HTMLElement>>('userInfo');

  highlightUser() {
    const element = this.userInfoElement();
    if (element) {
      element.nativeElement.style.backgroundColor = 'yellow';
    }
  }
}

La fonction viewChild() retourne un signal, ce qui signifie que sa valeur sera automatiquement mise à jour si l'élément change dans le DOM. Notez que viewChild() nous donne un ElementRef, ce qui signifie que nous pouvons accéder à l'élément natif avec nativeElement.

La syntaxe # est utilisée pour définir une "référence" dans le template. Une référence est une variable qui permet d'accéder à un élément du DOM ou d'un composant enfant.

Requête sur un composant enfant

Vous pouvez également utiliser viewChild() pour accéder à un composant enfant :

ts
import { Component, computed, viewChild, ElementRef } from '@angular/core';
import { UserHeaderComponent } from './user-header.component';

@Component({
  selector: 'app-user-card',
  standalone: true,
  imports: [UserHeaderComponent],
  template: `
    <app-user-header [title]="'Profil utilisateur'" #header />
    <div class="user-content">
      {{ user.name }}
    </div>
  `
})
export class UserCardComponent {
  // Accès au composant enfant
  header = viewChild(UserHeaderComponent);
  
  // Utilisation dans un signal computed
  headerTitle = computed(() => this.header()?.title());

  // Accès à l'élément DOM du composant enfant avec l'option read
  headerElement = viewChild('header', { read: ElementRef });
  headerNativeElement = computed(() => this.headerElement()?.nativeElement);
}
ts
import { Component, input } from '@angular/core';

@Component({
  selector: 'app-user-header',
  standalone: true,
  template: `<h1>{{ title() }}</h1>`
})
export class UserHeaderComponent {
  title = input<string>();
}

Puisque viewChild() retourne un signal, nous pouvons utiliser computed() pour créer un signal qui dépend d'un autre signal.

L'OPTION READ

L'option read permet de spécifier comment Angular doit lire la référence. Dans l'exemple ci-dessus, nous utilisons ElementRef pour accéder à l'élément DOM natif du composant enfant. Vous pouvez également utiliser d'autres tokens comme ViewContainerRef, TemplateRef, ou même des directives spécifiques.

Utiliser le décorateur @ViewChild

Avant Angular 17

Le décorateur @ViewChild est la façon traditionnelle de définir des requêtes de vue dans Angular avant la version 17.

La directive @ViewChild est utilisée pour accéder à un élément du DOM ou à un composant enfant dans un composant Angular. Elle permet de récupérer une référence à un élément HTML ou à un composant enfant dans le template du composant, ce qui permet de manipuler directement l'élément ou le composant dans le code TypeScript.


Voici comment utiliser @ViewChild dans un composant Angular :

  1. Déclarez @ViewChild en haut de votre classe de composant :
ts
import { Component, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <input type="text" #myInput>
  `,
})
export class AppComponent {
  @ViewChild('myInput') input!: ElementRef;
}
  1. Vous pouvez maintenant accéder à l'élément de votre template HTML dans votre composant en utilisant la propriété input. Par exemple, vous pouvez accéder à la valeur de l'input en utilisant this.input.nativeElement.value.

Voici un exemple complet et concret de l'utilisation de @ViewChild dans un composant Angular :

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

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <input type="text" #myInput>
    <button (click)="changeValue()">Modifier la valeur de l'input</button>
  `
})
export class AppComponent {
  @ViewChild('myInput') input!: ElementRef;

  changeValue() {
    this.input.nativeElement.value = 'Nouvelle valeur';
  }
}

Dans cet exemple, lorsque vous cliquerez sur le bouton, la valeur de l'input sera modifiée en "Nouvelle valeur".

ViewChild avec static: true

Par défaut, @ViewChild utilise static: false, ce qui signifie que la liaison se fait après l'initialisation du composant. Si vous avez besoin d'accéder à l'élément dès la création du composant, vous pouvez utiliser static: true :

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

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <input type="text" #myInput>
  `
})
export class AppComponent implements OnInit {
  @ViewChild('myInput', { static: true }) input!: ElementRef;

  ngOnInit() {
    // Vous pouvez accéder dans ngOnInit, ce qui n'était pas possible avec static: false
    console.log(this.input.nativeElement.value);
  }
}

ViewChild avec selecteur de composant

Vous pouvez également utiliser @ViewChild pour accéder à un composant enfant dans un composant parent. Pour cela, vous devez spécifier le type du composant enfant dans le décorateur @ViewChild :

ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <app-child />
  `,
  imports: [ChildComponent]
})
export class AppComponent implements AfterViewInit {
  @ViewChild(ChildComponent) childComponent!: ChildComponent;

  ngAfterViewInit() {
    // Vous pouvez accéder au composant enfant ici
    this.childComponent.someMethod();
  }
}
ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <h1>Composant enfant</h1>
  `
})
export class ChildComponent {
  someMethod() {
    console.log('Méthode du composant enfant appelée');
  }
}

ViewChild avec l'option read

Vous pouvez également utiliser l'option read pour accéder à des éléments spécifiques dans un composant ou un directive appliquée à un élément:

ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { NgClass } from '@angular/common';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <div #myDiv [ngClass]="cssClass">Contenu de la div</div>
  `,
  imports: [NgClass]
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myDiv', { read: NgClass }) myDiv!: NgClass;
  cssClass = '';

  ngAfterViewInit() {
    // Vous pouvez accéder à la directive NgClass appliquée à la div ici
    this.myDiv.add('highlight');
  }
}

Dans cet exemple, nous utilisons @ViewChild avec l'option read pour accéder à la directive NgClass appliquée à la div. Nous pouvons ensuite appeler la méthode add de la directive pour ajouter une classe CSS à la div.

ViewChild avec ng-template

Vous pouvez également utiliser @ViewChild pour accéder à un élément ng-template dans un composant :

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

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <ng-template #myTemplate>
      <p>Contenu du template</p>
    </ng-template>
  `
})
export class AppComponent {
  @ViewChild('myTemplate') myTemplate!: TemplateRef<any>;

  ngAfterViewInit() {
    // Vous pouvez accéder au contenu du template ici
    console.log(this.myTemplate);
  }
}

L'intérêt de cette approche est de pouvoir accéder au contenu du template et de l'utiliser dynamiquement dans le composant. Par exemple, vous pouvez insérer le contenu du template dans un élément du DOM en utilisant ViewContainerRef et TemplateRef:

ts
import { Component, ViewChild, TemplateRef, ViewContainerRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <ng-template #myTemplate>
      <p>Contenu du template</p>
    </ng-template>
    <div #container></div>
  `
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myTemplate') myTemplate!: TemplateRef<any>;
  @ViewChild('container', { read: ViewContainerRef }) container!: ViewContainerRef;

  ngAfterViewInit() {
    // Insérer le contenu du template dans le conteneur
    this.container.createEmbeddedView(this.myTemplate);
  }
}

Mais quels sont les cas d'usage de @ViewChild ? Quelques idées

Voici dix cas d'utilisation réels de la directive @ViewChild dans Angular, sans inclure de code :

  1. Accès à un élément du DOM :

    • Utiliser @ViewChild pour accéder directement à un élément HTML dans le composant pour manipuler ses propriétés (par exemple, focus, changement de style, etc.).
  2. Interaction avec des composants enfants :

    • Utiliser @ViewChild pour appeler des méthodes publiques ou accéder aux propriétés d'un composant enfant depuis le composant parent.
  3. Gestion des formulaires :

    • Accéder à un formulaire Angular pour réinitialiser le formulaire, valider les champs ou obtenir des valeurs de champ directement.
  4. Accès à des directives :

    • Accéder à une directive appliquée sur un élément HTML pour modifier son comportement.
  5. Intégration de bibliothèques tierces :

    • Utiliser @ViewChild pour intégrer et contrôler des bibliothèques JavaScript tierces (par exemple, des plugins jQuery) en manipulant directement le DOM.
  6. Création de composants dynamiques :

    • Utiliser @ViewChild pour obtenir une référence à une directive ng-template et créer dynamiquement des composants à cet emplacement.
  7. Déclenchement de changements de détection personnalisés :

    • Utiliser @ViewChild pour accéder aux éléments qui ne déclenchent pas automatiquement la détection des changements, et appeler manuellement changeDetectorRef.detectChanges().
  8. Contrôle des animations :

    • Accéder aux éléments HTML ou aux composants pour contrôler les animations (démarrage, arrêt, pause) en fonction de certaines conditions ou événements.
  9. Manipulation des événements utilisateur :

    • Attacher des écouteurs d'événements personnalisés aux éléments du DOM pour des interactions utilisateur plus complexes qui ne sont pas gérées par Angular par défaut.
  10. Test et Debugging :

    • Utiliser @ViewChild pour accéder aux composants enfants ou aux éléments DOM pendant les tests pour vérifier leur état ou simuler des interactions utilisateur.

Chaque mois, recevez en avant-première notre newsletter avec les dernières actualités, tutoriels, astuces et ressources Angular directement par email !