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 !

Skip to content

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

Comprendre et Utiliser les Sélecteurs dans NgXs

Introduction:

NgXS offre une méthode déclarative pour accéder aux états grâce aux sélecteurs. Ces sélecteurs sont des fonctions qui peuvent être utilisées pour récupérer des portions de l'état. Nous allons détailler le fonctionnement des sélecteurs et comment les utiliser dans un composant Angular.

Pour suivre ce contenu, il faut déjà avoir créer l'état et l'action (voir Créer un état et Créer une action). Sinon, regardez le code en entier à la fin de ce contenu 😃

1. Qu'est-ce qu'un sélecteur ?

Un sélecteur est une méthode statique, décorée avec @Selector(), à l'intérieur d'une classe State. Il permet de récupérer une partie ou l'ensemble des données stockées dans un état. Les sélecteurs sont optimisés pour éviter des recalculs inutiles, rendant l'accès à l'état performant.

2. Création et utilisation du sélecteur getUsersList:

2.1. Définir le sélecteur:

Dans notre UserState (src/app/store/users.state.ts), nous avons le sélecteur getUsersList:

typescript
@Selector()
static getUsersList(state: UserStateModel): User[] {
    return state.usersList
}

Ce sélecteur retourne simplement la liste des utilisateurs depuis l'état.

3. Comment utiliser le sélecteur dans un composant:

3.1. Utilisez le décorateur @Select:

NgXS fournit un décorateur pratique, @Select, qui peut être utilisé pour injecter directement un Observable représentant une partie de l'état dans votre composant.

Dans UsersComponent, nous utilisons ce décorateur:

typescript
users$: Observable<User[]> = this.select(UserState.getUsersList)

Cela crée un Observable users$ qui émettra la liste des utilisateurs chaque fois qu'elle est mise à jour dans l'état.

3.2. Utilisation dans le template:

Dans le fichier users.component.html, vous pouvez utiliser users$ avec la pipe async pour itérer sur la liste des utilisateurs:

angular-html
@for (user of users$ | async ; track user.id) {
    <div class="user">
        <div class="user__name">{{ user.name }}</div>
        <div class="user__email">{{ user.email }}</div>
    </div>
}

3.3. Charger des données:

La méthode ngOnInit est utilisée pour déclencher l'action GetUsersAction qui récupère les utilisateurs:

typescript
ngOnInit() {
    this.store.dispatch(new GetUsersAction())
}

Code en entier

ts
import { Injectable, inject } from "@angular/core";
import { Action, State, StateContext, Selector } from "@ngxs/store";
import { Observable, tap } from "rxjs";
import { User } from "src/app/core/interfaces/user";
import { UserService } from "src/app/core/services/user.service";
import { GetUsersAction } from "./users.action";

export interface UserStateModel {
    usersList: User[]
}

@State({
    name: 'users',
    defaults: {
        usersList: []
    }
})
@Injectable()
export class UserState {
    private userService = inject(UserService)

    @Selector()
    static getUsersList(state: UserStateModel): User[] {
        return state.usersList
    }

    @Action(GetUsersAction)
    getUsers(context: StateContext<UserStateModel>, action: GetUsersAction): Observable<any> {
        return this.userService.getAll(action.sort)
            .pipe(
                tap((users: User[]) => {
                    context.patchState({
                        usersList: users
                    })
                })
            )
    }
}
ts
export class GetUsersAction {
    static readonly type = '[Users] Get Users';
    constructor(public sort: string) {}
}
ts
import { Component, OnInit, inject } from '@angular/core'
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { User } from 'src/app/core/user';
import { GetUsersAction } from 'src/app/store/users.action';
import { UserState } from 'src/app/store/users.state';

@Component({
    selector: 'app-users',
    templateUrl: 'users.component.html'
})
export class UsersComponent implements OnInit {
    private store = inject(Store)
    users$: Observable<User[]> = this.select(UserState.getUsersList)

    ngOnInit() {
        this.store.dispatch(new GetUsersAction())
    }
}
angular-html
@for (user of users$ | async ; track user.id) {
    <div class="user">
        <div class="user__name">{{ user.name }}</div>
        <div class="user__email">{{ user.email }}</div>
    </div>
}
ts
import { HttpClient } from "@angular/common/http";
import { Injectable, inject } from "@angular/core";
import { Observable } from "rxjs";
import { User } from "./user";

@Injectable({
  providedIn: "root",
})
export class UserService {
  private http = inject(HttpClient);
  readonly url: string = "https://jsonplaceholder.typicode.com/users";

  getAll(): Observable<User[]> {
    return this.http.get<User[]>(this.url);
  }
}
ts
export interface User {
    id: number;
    name: string;
    username?: string;
    email: string;
    address?: {
        street: string;
        suite: string;
        city: string;
        zipcode: string;
        geo: {
            lat: string;
            lng: string;
        }
    };
    phone?: string;
    website?: string;
    company?: {
        name: string;
        catchPhrase: string;
        bs: string;
    };
}

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