Un loader UX-friendly en Angular avec cet utilitaire RxJS



This content originally appeared on DEV Community and was authored by Romain Geffrault

🌀 Un loader UX-friendly en Angular avec RxJS

Afficher un loader trop rapidement peut provoquer un effet de “flash” désagréable. À l’inverse, le masquer trop tôt peut perturber l’utilisateur. Voici une solution simple et réutilisable avec RxJS pour un loader intelligent et fluide.

Lien stackblitz.

🎯 Objectif

  • Ne pas afficher le loader avant 200 ms, pour éviter les flashs inutiles.
  • Une fois qu’il est affiché, le maintenir visible au moins 2 secondes, pour assurer une expérience utilisateur stable.
  • Masquer le loader uniquement quand l’API a terminé de charger et que les 2 secondes sont écoulées.

🔧 Le code

// Timer déclenché après 200ms
const _passed200ms = timer(200).pipe(
  map(() => true),
  startWith(false)
);

// Timer déclenché après 2 secondes
const _passed2sDisplay = timer(2000).pipe(
  map(() => true),
  startWith(false)
);

// Fonction principale : retourne un Observable<boolean> à consommer dans le template
function uiLoading$(isLoading$: Observable<boolean>) {
  return combineLatest([_passed200ms, _passed2sDisplay, isLoading$]).pipe(
    tap((data) => console.log('data', data)),
    map(([passed200ms, passed2sDisplay, isApiStillLoading]) => {
      if (!passed200ms) return false; // Ne rien afficher avant 200ms
      if (isApiStillLoading) return true; // Affiche le loader si l'API charge encore
      return !passed2sDisplay ? true : false; // Attendre les 2s sinon
    }),
    distinctUntilChanged()
  );
}

🧪 Cas d’usage

🔹 Cas 1 : API lente → loader visible de 200ms à 5s

uiLoading$(
  of('data').pipe(
    delay(5000),
    map(() => false),
    startWith(true)
  )
).subscribe(result => console.log('result', result));

🔹 Cas 2 : API très rapide → le loader ne s’affiche jamais

uiLoading$(
  of('data').pipe(
    delay(50),
    map(() => false),
    startWith(true)
  )
).subscribe(result => console.log('result', result));

🔹 Cas 3 : API rapide mais pas instantanée → loader visible entre 200ms et 2s

uiLoading$(
  of('data').pipe(
    delay(1500),
    map(() => false),
    startWith(true)
  )
).subscribe(result => console.log('result', result));

✅ Avantages

  • 100 % réactif, sans variable d’état local ou setTimeout.
  • Composable : peut être utilisé dans n’importe quel composant Angular.
  • UX fluide : améliore la perception du chargement côté utilisateur.

Conseil perso: Fait en sorte de souscrire à cet observable directement dans ton template, cela va permettre au loader de s’adapter en conséquence.

Je m’excuse, je partage rapidement cet utilitaire, sans implémentation concrète. Toutefois, si tu as des questions ou si tu souhaites un example d’implémentation n’hésite pas.

Si l’article t’a plu ou si tu as des questions, n’hésite pas à laisser un commentaire ou encore à me suivre sur linkedin Romain Geffrault.


This content originally appeared on DEV Community and was authored by Romain Geffrault