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.

Gérer le responsive design avec BreakpointObserver avec Angular CDK

Le responsive design est essentiel pour créer des applications web modernes qui s'adaptent à tous les écrans. Ici, nous allons voir comment utiliser BreakpointObserver d'Angular CDK pour gérer dynamiquement l'affichage de notre application.

Installation d'Angular CDK

Commençons par installer Angular CDK :

bash
npm install @angular/cdk

Qu'est-ce que Angular CDK ?

Angular CDK est un ensemble d'outils de développement qui fournit des composants réutilisables et des services pour créer des fonctionnalités complexes dans les applications Angular. Il offre des solutions pour la gestion des overlays, du drag & drop, des tables virtuelles, de l'accessibilité et bien d'autres fonctionnalités, sans imposer de style visuel spécifique. C'est la base sur laquelle Angular Material est construit, mais il peut être utilisé indépendamment pour créer vos propres composants personnalisés.

Implémentation

Voici comment utiliser BreakpointObserver dans un composant :

ts
import { Component } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { inject } from '@angular/core';
import { map } from 'rxjs';
import { AsyncPipe } from '@angular/common';

@Component({
  selector: 'app-user',
  standalone: true,
  imports: [AsyncPipe],
  template: `
    @if (isDesktop$ | async) {
      <div class="desktop-view">
        <h2>Vue Desktop</h2>
      </div>
    } @else {
      <div class="mobile-view">
        <h2>Vue Mobile</h2>
      </div>
    }
  `
})
export class UserComponent {
  private breakpointObserver = inject(BreakpointObserver);
  
  isDesktop$ = this.breakpointObserver
    .observe([Breakpoints.Tablet, Breakpoints.Large, Breakpoints.XLarge])
    .pipe(map(result => result.matches));
}
  1. this.breakpointObserver.observe([...]) :

    • Cette méthode utilise le BreakpointObserver pour surveiller les changements de taille d'écran.
    • Les breakpoints spécifiés (Breakpoints.Tablet, Breakpoints.Large, Breakpoints.XLarge) correspondent à différentes largeurs d'écran.
    • Le BreakpointObserver émet un événement chaque fois que l'écran entre ou sort de l'un de ces breakpoints.
  2. .pipe(map(result => result.matches)) :

    • pipe est une méthode utilisée pour transformer les données émises par un observable.
    • map est un opérateur qui prend chaque valeur émise par l'observable et la transforme.
    • Dans ce cas, result.matches est un booléen qui indique si l'écran correspond à l'un des breakpoints spécifiés. Si c'est le cas, result.matches sera true, sinon false.
  3. isDesktop$ | async : Le AsyncPipe souscrit à l'observable isDesktop$ et met à jour le template chaque fois que la valeur change.

    • Cela permet de réagir dynamiquement aux changements de taille d'écran sans avoir à gérer manuellement la souscription et la désinscription de l'observable.

En savoir plus : AsyncPipe

En utilisant un signal

Les signaux offrent une alternative moderne aux observables pour gérer l'état réactif. Voici comment utiliser BreakpointObserver avec les signaux :

ts
import { Component } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { inject } from '@angular/core';
import { map } from 'rxjs';
import { toSignal } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-user',
  standalone: true,
  template: `
    @if (isDesktop()) {
      <div class="desktop-view">
        <h2>Vue Desktop</h2>
      </div>
    } @else {
      <div class="mobile-view">
        <h2>Vue Mobile</h2>
      </div>
    }
  `
})
export class UserComponent {
  private breakpointObserver = inject(BreakpointObserver);
  
  isDesktop = toSignal(
    this.breakpointObserver
      .observe([Breakpoints.Tablet, Breakpoints.Large, Breakpoints.XLarge])
      .pipe(map(result => result.matches)),
    { initialValue: false }
  );
}

AVANTAGES DES SIGNAUX

  • Syntaxe plus simple dans le template (pas besoin du pipe async)
  • Meilleure performance car moins de cycles de détection de changements

INITIALVALUE

N'oubliez pas de spécifier une initialValue lors de la conversion d'un observable en signal pour éviter les valeurs undefined au démarrage de l'application.

Vous pouvez également créer un service utilisant les signaux :

ts
import { Injectable, inject } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { map } from 'rxjs';
import { toSignal } from '@angular/core/rxjs-interop';

@Injectable({
  providedIn: 'root'
})
export class LayoutService {
  private breakpointObserver = inject(BreakpointObserver);

  isDesktop = toSignal(
    this.breakpointObserver
      .observe([Breakpoints.Tablet, Breakpoints.Large, Breakpoints.XLarge])
      .pipe(map(result => result.matches)),
    { initialValue: false }
  );
}
ts
import { AsyncPipe } from '@angular/common';
import { LayoutService } from './layout.service';

@Component({
  selector: 'app-user',
  standalone: true,
  template: `
    @if (isDesktop()) {
      <div class="desktop-view">
        <h2>Vue Desktop</h2>
      </div>
    } @else {
      <div class="mobile-view">
        <h2>Vue Mobile</h2>
      </div>
    }
  `
})
export class UserComponent {
  private layoutService = inject(LayoutService);
  isDesktop = this.layoutService.isDesktop;
}

Bonnes pratiques

  1. Unsubscribe : N'oubliez pas de vous désabonner de l'observable si vous l'utilisez directement dans le code (bien que dans notre exemple, le pipe async gère cela automatiquement).

  2. Performance : Évitez de créer trop d'observateurs de breakpoints dans votre application. Idéalement, créez un service qui centralise cette logique (voir l'exemple ci-dessus).

Les breakpoints disponibles

BreakpointObserver propose plusieurs breakpoints prédéfinis :

BreakpointMedia QueryDescription
XSmall(max-width: 599.98px)Pour les très petits écrans (smartphones en mode portrait)
Small(min-width: 600px) and (max-width: 959.98px)Pour les petits écrans (smartphones en mode paysage et petites tablettes)
Medium(min-width: 960px) and (max-width: 1279.98px)Pour les écrans moyens (tablettes et petits ordinateurs portables)
Large(min-width: 1280px) and (max-width: 1919.98px)Pour les grands écrans (ordinateurs de bureau standards)
XLarge(min-width: 1920px)Pour les très grands écrans (moniteurs haute résolution)
Handset(max-width: 599.98px) and (orientation: portrait), (max-width: 959.98px) and (orientation: landscape)Pour les appareils mobiles, quelle que soit l'orientation
Tablet(min-width: 600px) and (max-width: 839.98px) and (orientation: portrait), (min-width: 960px) and (max-width: 1279.98px) and (orientation: landscape)Pour les tablettes, en tenant compte de l'orientation
Web(min-width: 840px) and (orientation: portrait), (min-width: 1280px) and (orientation: landscape)Pour les écrans d'ordinateur, quelle que soit l'orientation
HandsetPortrait(max-width: 599.98px) and (orientation: portrait)Pour les appareils mobiles en mode portrait uniquement
TabletPortrait(min-width: 600px) and (max-width: 839.98px) and (orientation: portrait)Pour les tablettes en mode portrait uniquement
WebPortrait(min-width: 840px) and (orientation: portrait)Pour les écrans d'ordinateur en mode portrait
HandsetLandscape(max-width: 959.98px) and (orientation: landscape)Pour les appareils mobiles en mode paysage uniquement
TabletLandscape(min-width: 960px) and (max-width: 1279.98px) and (orientation: landscape)Pour les tablettes en mode paysage uniquement
WebLandscape(min-width: 1280px) and (orientation: landscape)Pour les écrans d'ordinateur en mode paysage

PERSONNALISATION

Vous pouvez aussi créer vos propres breakpoints personnalisés :

ts
const customBreakpoint = '(min-width: 500px)';
this.breakpointObserver.observe([customBreakpoint])

ATTENTION

Les breakpoints doivent être choisis en fonction des besoins spécifiques de votre application. Ne vous contentez pas de copier-coller les valeurs par défaut sans réflexion.

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