Les nouveautés d'Angular 19 en 4 minutes

Angular 19 vient de sortir, et il y a beaucoup de nouveautés intéressantes : hydratation incrémentale, linkedSignal, l'API des ressources, et plein d'autres choses. Venez découvrir tout ça en moins de 4 minutes !

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.

Récupérer les informations de route avec withComponentInputBinding()

Compatibilité

Cette fonctionnalité est disponible depuis Angular 16.

La transmission d'informations entre les composants est un besoin courant dans une application Angular. Nous allons voir comment utiliser withComponentInputBinding() pour passer et récupérer des données de manière élégante.

Pourquoi utiliser withComponentInputBinding() ?

Imaginez que vous développez une application de gestion de bibliothèque. Avant, pour afficher les détails d'un livre à partir de son ID dans l'URL, vous deviez injecter le service ActivatedRoute, vous abonner aux changements, et extraire manuellement les paramètres. C'était verbeux et répétitif. Avec withComponentInputBinding(), c'est comme si vous aviez un assistant qui transmet automatiquement ces informations à votre composant !

Pourquoi utiliser withComponentInputBinding() ?

  • Injection simplifiée des données du routeur : Au lieu d'injecter ActivatedRoute et d'extraire manuellement les données, vous pouvez simplement déclarer des entrées de composants portant les mêmes noms que les clés de données du routeur, et withComponentInputBinding() les remplira automatiquement.
  • Découplage : Les composants n'ont plus besoin de connaître le routeur ou ActivatedRoute pour accéder aux données de la route. Cela permet de découpler la logique du composant de l'implémentation du routeur.
  • Amélioration de l'organisation du code : L'utilisation d'entrées de composants permet de concentrer la logique des composants sur leurs responsabilités principales, tandis que l'injection des données du routeur est gérée séparément.
  • Tests plus faciles : Avec withComponentInputBinding(), vous pouvez tester vos composants plus facilement, car les données du routeur sont injectées automatiquement et vous n'avez pas besoin de simuler ou de bloquer ActivatedRoute.

1. Définition des routes

Créons nos routes pour gérer les utilisateurs :

ts
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'users/:id',
    component: UserComponent
  }
];

2. Configuration du Router

D'abord, nous devons activer la liaison automatique des paramètres de route aux inputs des composants :

ts
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { ApplicationConfig } from '@angular/core';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, withComponentInputBinding())
  ]
};

HÉRITAGE DES PARAMÈTRES

Imaginons que vous ayez une structure de routes imbriquées comme ceci :

- /users/:userId (route parent)
  - /users/:userId/posts/:postId (route enfant)

Par défaut, le composant de la route enfant n'a accès qu'à son propre paramètre postId. Avec paramsInheritanceStrategy: 'always', le composant enfant pourra aussi accéder au userId de la route parente.

ts
import { provideRouter, withComponentInputBinding, withRouterConfig } from '@angular/router';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, 
      withComponentInputBinding(),
      withRouterConfig({
        paramsInheritanceStrategy: 'always'
      })
    )
  ]
};

3. Création du composant

Voici comment récupérer l'ID de l'utilisateur dans notre composant :

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

@Component({
  standalone: true,
  selector: 'app-user',
  imports: [AsyncPipe],
  template: `
    @if (user$ | async; as user) {
      <div>
        <h2>{{ user.name }}</h2>
        <p>{{ user.email }}</p>
      </div>
    }
  `
})
export class UserComponent {
  private userService = inject(UserService);
  user$!: Observable<User>;

  @Input()
  set id(userId: string) {
    this.user$ = this.userService.getUser(userId);
  }
}

ASTUCE

L'utilisation de set avec l'Input permet de réagir automatiquement aux changements de paramètres de route, même si l'utilisateur navigue entre différents profils sans changer de composant.

4. Navigation vers l'utilisateur

Pour naviguer vers un utilisateur spécifique :

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

@Component({
  standalone: true,
  selector: 'app-home',
  template: `
    @for (user of users; track user.id) {
      <div>
        <span>{{ user.name }}</span>
        <button (click)="navigateToUser(user.id)">Voir le profil</button>
      </div>
    }
  `
})
export class HomeComponent {
  private router = inject(Router);
  
  navigateToUser(userId: number) {
    this.router.navigate(['/users', userId]);
  }
}

ATTENTION

Assurez-vous que les types de paramètres correspondent entre votre route et votre Input. Si votre route attend un nombre mais que vous recevez une chaîne, vous devrez faire la conversion appropriée.

Les données statiques avec data

Imaginons que vous ayez un site e-commerce. Chaque catégorie de produits a un titre et une description spécifique. Au lieu de coder en dur ces informations dans les composants, vous pouvez les définir dans les routes.

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

@Component({
  standalone: true,
  selector: 'app-user-list',
  template: `
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
    @if (role === 'admin') {
      <button>Ajouter un utilisateur</button>
    }
  `
})
export class UserListComponent {
  @Input() title = '';
  @Input() description = '';
  @Input() role = '';
}
ts
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'users',
    component: UserListComponent,
    data: {
      title: 'Liste des utilisateurs',
      description: 'Gérez tous vos utilisateurs',
      role: 'admin'
    }
  }
];

Les Resolvers pour le chargement de données

Plus d'infos sur les resolvers ici.

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

@Component({
  standalone: true,
  selector: 'app-user',
  template: `
    <div>
      <h2>{{ user.name }}</h2>
      <p>{{ user.email }}</p>
    </div>
  `
})
export class UserComponent {
  @Input() user!: User;
}
ts
import { Routes } from '@angular/router';
import { userResolver } from './user.resolver';

export const routes: Routes = [
  {
    path: 'users/:id',
    component: UserComponent,
    resolve: {
      user: userResolver
    }
  }
];
ts
import { ResolveFn } from '@angular/router';
import { inject } from '@angular/core';
import { UserService } from './user.service'; // Le service qui utiliser pour récupérer les données

export const userResolver: ResolveFn<User> = (route) => {
  const userService = inject(UserService);
  return userService.getUser(route.paramMap.get('id')!);
};

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