Qu’est-ce qu’Angular ?
Angular est un framework d’application complet maintenu par Google. Alors que React est une bibliothèque autour de laquelle vous assemblez une stack, Angular livre la stack complète : composants, routage, formulaires, HTTP, injection de dépendances, tests et une CLI puissante, le tout conçu pour fonctionner ensemble. Il privilégie TypeScript et impose une structure précise, ce qui explique pourquoi les grandes équipes le choisissent.
Cette exhaustivité est le principal compromis. Vous acceptez une courbe d’apprentissage plus raide et davantage de conventions de framework en échange d’une cohérence, d’un outillage robuste et de moins de décisions architecturales à prendre de zéro. Pour un petit prototype, cela peut sembler lourd ; pour une base de code d’entreprise sur cinq ans, c’est souvent un soulagement.
Composants et templates
Un composant est une classe TypeScript décorée avec @Component, associée à un template HTML et à des styles optionnels.
// user-card.component.ts
import { Component, Input } from "@angular/core";
@Component({
selector: "app-user-card",
standalone: true,
template: `
<article class="card">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
</article>
`,
})
export class UserCardComponent {
@Input({ required: true }) user!: { name: string; email: string };
}
Le template utilise {{ }} pour l’interpolation et des directives pour la logique. Les versions modernes d’Angular utilisent des blocs de flux de contrôle (control flow) intégrés au lieu des anciennes directives structurelles.
<!-- list.html -->
@if (users.length > 0) {
<ul>
@for (user of users; track user.id) {
<li>{{ user.name }}</li>
}
</ul>
} @else {
<p>No users yet.</p>
}
L’expression track dans @for joue le même rôle qu’une clé dans React ou Vue : elle indique à Angular comment faire correspondre les éléments entre deux mises à jour.
Liaison de données (Data binding)
Les templates Angular prennent en charge quatre types de liaison.
- L’interpolation
{{ value }}affiche une valeur sous forme de texte. - La liaison de propriété (Property binding)
[src]="url"définit une propriété d’élément à partir d’une expression. - La liaison d’événement (Event binding)
(click)="save()"appelle une méthode lorsqu’un événement se déclenche. - La liaison bidirectionnelle (Two-way binding)
[(ngModel)]="name"combine les deux pour les champs de formulaire.
<!-- bindings.html -->
<img [src]="user.avatar" [alt]="user.name" />
<button (click)="save()">Save</button>
<input [(ngModel)]="query" />
La liaison bidirectionnelle est pratique pour les formulaires simples, mais pour tout ce qui nécessite une validation, les formulaires réactifs (reactive forms) sont généralement plus appropriés.
Signals
Les Signals sont la primitive de réactivité moderne d’Angular. Un signal détient une valeur et notifie les consommateurs intéressés lorsqu’elle change, ce qui permet au framework de mettre à jour uniquement les parties de la vue qui en dépendent.
// cart.component.ts
import { Component, signal, computed } from "@angular/core";
@Component({
selector: "app-cart",
standalone: true,
template: `<p>Total: {{ total() }}</p>`,
})
export class CartComponent {
items = signal([{ price: 10 }, { price: 20 }]);
total = computed(() =>
this.items().reduce((sum, i) => sum + i.price, 0),
);
add(price: number) {
this.items.update((items) => [...items, { price }]);
}
}
computed dérive une valeur à partir d’autres signals et la met en cache jusqu’à ce qu’une dépendance change. effect exécute un effet de bord lorsque les signals qu’il lit sont modifiés. Ensemble, ils couvrent la majorité des besoins des composants.
RxJS et observables
Angular possède une intégration profonde de RxJS. Un observable représente un flux de valeurs au fil du temps, et les opérateurs vous permettent de transformer et de combiner ces flux.
// search.component.ts
import { Component } from "@angular/core";
import { toSignal } from "@angular/core/rxjs-interop";
import { debounceTime, distinctUntilChanged, switchMap } from "rxjs";
@Component({ /* ... */ })
export class SearchComponent {
private query$ = new Subject<string>();
results = toSignal(
this.query$.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap((q) => this.api.search(q)),
),
{ initialValue: [] },
);
}
C’est là que RxJS prend tout son sens : le debouncing, l’annulation de requêtes obsolètes et la combinaison de flux sont difficiles à exprimer avec de simples promises. Pour un état synchrone simple, les signals sont plus simples. Le Angular moderne vous permet de mélanger les deux et de convertir via toSignal et toObservable.
Services et injection de dépendances
La logique et les données partagées appartiennent aux services, et non aux composants. L’injection de dépendances permet de les fournir partout où ils sont nécessaires.
// users.service.ts
import { Injectable, inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
@Injectable({ providedIn: "root" })
export class UsersService {
private http = inject(HttpClient);
getAll() {
return this.http.get<User[]>("/api/users");
}
}
// users.component.ts
export class UsersComponent {
private users = inject(UsersService);
list = toSignal(this.users.getAll(), { initialValue: [] });
}
providedIn: "root" enregistre un singleton pour l’ensemble de l’application. L’injection de dépendances facilite le remplacement des services lors des tests et permet aux composants de rester concentrés sur la présentation.
Routage
Le routeur Angular associe des URLs à des composants et prend en charge les routes imbriquées, les guards, les resolvers et le lazy loading.
// app.routes.ts
import { Routes } from "@angular/router";
export const routes: Routes = [
{ path: "", component: HomeComponent },
{ path: "users/:id", component: UserProfileComponent },
{
path: "admin",
loadChildren: () => import("./admin/admin.routes").then((m) => m.ADMIN_ROUTES),
},
];
Le lazy loading des zones fonctionnelles permet de garder le bundle initial léger, tandis que les guards vous permettent de bloquer la navigation jusqu’à ce qu’une condition, telle que l’authentification, soit remplie.
Formulaires et HTTP
Angular propose deux approches pour les formulaires. Les Reactive forms définissent le modèle et les validateurs dans la classe, ce qui permet une meilleure scalabilité et facilite les tests. Les Template-driven forms utilisent des directives comme ngModel et sont plus rapides à mettre en œuvre pour des cas simples.
// signup.component.ts
form = new FormGroup({
email: new FormControl("", [Validators.required, Validators.email]),
password: new FormControl("", [Validators.required, Validators.minLength(8)]),
});
submit() {
if (this.form.invalid) return;
this.http.post("/api/signup", this.form.getRawValue()).subscribe();
}
HttpClient retourne des observables, ainsi les requêtes peuvent être composées avec des opérateurs RxJS pour gérer les tentatives (retries), l’annulation et la gestion des erreurs.
Bonnes pratiques
- Privilégiez les standalone components et les signals pour le nouveau code.
- Gardez vos composants concentrés sur la présentation et déplacez la logique dans des services.
- Utilisez les reactive forms pour tout ce qui nécessite une validation ou des champs dynamiques.
- Implémentez le lazy-loading pour les zones fonctionnelles afin de limiter la taille du bundle initial.
- Utilisez la détection de changements
OnPushou les signals pour limiter les vérifications inutiles. - Suivez les éléments dans
@foravec une valeur unique stable. - Désabonnez-vous des observables à longue durée de vie, ou utilisez le pipe async et
toSignal.
Erreurs courantes
- Placer la logique métier dans les composants plutôt que dans les services.
- S’abonner manuellement et oublier de se désabonner, provoquant ainsi des fuites de mémoire.
- Utiliser RxJS alors qu’un signal serait plus simple.
- Muter directement la valeur d’un signal au lieu d’utiliser
setouupdate. - Créer un seul NgModule énorme au lieu de routes de fonctionnalités chargées en lazy-loading.
- Traiter Angular comme React et lutter contre la structure du framework.
Et après ?
Angular récompense la patience grâce à une structure qui s’inscrit dans la durée. Approfondissez vos connaissances en TypeScript, comprenez comment il se compare à React et Vue, et découvrez l’outillage Node.js qui propulse sa CLI. Ensuite, créez une fonctionnalité incluant du routing, un service et un formulaire réactif pour voir comment toutes ces pièces s’assemblent.