Jusqu'à -30%, seulement jusqu'au 30/06 :
livres en ligne, vidéos & formations. Cliquez ici
Jusqu'au 30/06 : En cliquant ici, bénéficiez jusqu'à
30% de réduction sur votre panier. Je découvre !
  1. Livres & vidéos
  2. Angular
  3. Naviguer entre les pages
Extrait - Angular Développez vos applications web avec le framework JavaScript de Google (4e édition)
Extraits du livre
Angular Développez vos applications web avec le framework JavaScript de Google (4e édition)
1 avis
Revenir à la page d'achat du livre

Naviguer entre les pages

Introduction

Dans une application web traditionnelle, chaque changement de page nécessite un rechargement complet du contenu depuis le serveur. Cela entraîne souvent des temps de réponse plus longs et une mauvaise expérience utilisateur car le chargement complet est visible et bloque toute autre action. Avec l’avènement des Single Page Applications (SPA), comme celles développées avec Angular, l’expérience utilisateur a été considérablement améliorée en permettant de naviguer entre différentes vues sans avoir à recharger toute la page.

Le routage joue un rôle crucial, il permet de définir des chemins spécifiques dans l’application, liant chaque URL à une vue ou un composant particulier. En d’autres termes, selon le navigateur, il n’y a qu’un seul fichier HTML chargé. Cependant, on va modifier son contenu en chargeant des éléments dynamiquement, ce qui permet à l’utilisateur de naviguer entre les différentes parties d’une application sans quitter la page en cours.

Contrairement à d’autres librairies de SPA, Angular fournit son propre système de routage, convenant à toute taille d’application, avec lequel nous pouvons notamment définir des routes plus ou moins complexes, ajouter une notion de chargement différé...

Mise en place rapide

1. Configuration des routes

Commençons tout de suite avec la marche à suivre, pas à pas, pour que ce soit parlant, puis nous reviendrons en détail sur les différents éléments utilisés.

Prenons l’exemple d’une application qui contient deux composants représentant de futures pages : HomePageComponent et AboutPageComponent.

Nous ajoutons la configuration des différentes routes dans un fichier dédié, par exemple le standard pour les routes globales à toute l’application : app.routes.ts. Un objet Route est un objet qui contient plusieurs paramètres de configuration ; nous allons au plus simple pour le moment, en spécifiant le path qui est littéralement la route, et component, le composant représentant la page pour le chemin donné. Ajoutons deux routes comme suit :

export const routes: Routes = [ 
  { 
    path: '', 
    component: HomePageComponent, 
  }, 
  { 
    path: 'about', 
    component: AboutPageComponent, 
  }, 
]; 

Maintenant, il faut informer Angular que nous avons une liste de routes à prendre en compte. Ainsi, dans le fichier de configuration, il faudra ajouter un Router dans...

Les routes en détail

1. Structure d’une route

Chaque route est définie par un objet qui regroupe plusieurs propriétés permettant de contrôler la navigation et le rendu des composants. Voici ci-dessous les principales propriétés à connaître, avant que l’on en voie d’autres dans les sections suivantes.

La première est path, qui correspond au segment d’URL associé à cette route. Il permet de lier une URL spécifique à une fonctionnalité ou un composant de l’application. Lorsqu’un utilisateur accède à cette URL, Angular détermine si elle correspond à ce chemin pour afficher le contenu approprié. En effet, le routeur va regarder les routes une par une dans l’ordre et sélectionnera la première qui correspond.

images/09El01.png

Ensuite, la propriété component permet de spécifier le composant à afficher lorsque la route correspondante est activée. Par exemple, une route comme "/home" pourrait afficher un composant d’accueil, tandis qu’une autre route mènerait à une page d’administration ou de profil.

Si plusieurs URL partagent un même composant, la propriété redirectTo permet de rediriger automatiquement l’utilisateur vers une autre route.

Exemple :

const routes: Routes = [ 
  { path: '', redirectTo: '/home', pathMatch: 'full' }, 
  { path: 'home', component: HomeComponent } 
]; 

On notera l’utilisation de la propriété pathMatch. Cette propriété permet de préciser comment Angular doit comparer des chemins pour trouver la bonne correspondance. Par défaut, la valeur est prefix. Avec cette valeur, la comparaison entre l’URL et les routes est plutôt souple. Dans certains cas comme des routes ambiguës pour le routeur ou bien lorsque l’on veut avoir une redirection sur des chemins vides comme dans l’exemple ci-dessus, il est nécessaire de rajouter la propriété avec la valeur full. Ce qui forcera la comparaison à être exacte.

Les routes peuvent également être organisées de manière hiérarchique grâce à la propriété children. Cette dernière...

Guards de protection des routes

1. Introduction

Dans une application, il est souvent nécessaire de restreindre l’accès à certaines routes ou d’effectuer des vérifications avant de permettre la navigation. Par exemple, vous pourriez vouloir empêcher un utilisateur non authentifié d’accéder à des pages protégées, ou demander une confirmation avant de quitter une page avec des données non sauvegardées. C’est là qu’interviennent les gardes (guards).

Ils peuvent être définis comme de simples fonctions (méthode courante) ou bien en tant que classes (façon de faire dépréciée) qui peuvent contrôler le flux de navigation. Ils sont très proches des fonctions d’interception vues dans le chapitre Les signaux sur les services, et il en existe six types correspondant à des moments clés de la navigation :

  • canActivate : il empêche ou autorise l’accès à une route en fonction de conditions données.

  • canActivateChild : il est similaire au précédent mais s’applique aux routes enfants d’un module ou d’une section spécifique.

  • canDeactivate : il contrôle le fait de quitter une route en fonction de conditions (par exemple pour demander une confirmation avant de quitter une page sans sauvegarder les données).

  • canMatch : il contrôle la comparaison d’une URL face aux différentes routes configurées, ce qui peut permettre de sauter une route pour correspondre à une route suivante dans la liste.

  • resolve : il permet de précharger des données avant la navigation.

  • canLoad : il contrôle le chargement d’un segment en chargement différé en fonction de conditions. Cependant, nous ne verrons pas celui-ci en détail car il est maintenant déprécié en faveur de canMatch.

2. Mise en place

a. CanActivate

Le guard CanActivate est sans doute le plus répandu ; il va nous permettre de vérifier si l’utilisateur courant a le droit d’accéder à une route avant que la navigation s’effectue. Créons ensemble le guard :

ng g g --skip-tests guards/isAuth 

Il est possible de directement passer en paramètre le type de guard voulu, sinon la...

Gestion des erreurs

Bien que les routes simples aient peu de chances d’échouer, il devient crucial de porter une attention particulière à la gestion des erreurs lorsque vous commencez à manipuler des routes dynamiques ou à mettre en place des hiérarchies complexes de navigation. Les erreurs peuvent survenir dans des scénarios plus sophistiqués, comme les routes paramétrées, les modules chargés en lazy loading ou les transitions entre des sections imbriquées. Il est donc essentiel d’anticiper et de gérer ces erreurs pour garantir une navigation fluide et une expérience utilisateur optimale.

1. Wildcard

La première étape essentielle consiste à mettre en place une route générique dite wildcard. Le path de cette route veut tout simplement dire qu’il correspondra avec n’importe quelle entrée. Cela permet d’éviter que l’utilisateur ne se retrouve sur une page blanche ou face à une erreur après avoir saisi une URL incorrecte.

const routes: Routes = [ 
  { path: 'home', component: HomeComponent }, 
  { path: 'about', component: AboutComponent }, 
  { path: '**', redirectTo: 'home'} 
]; 

Attention car le routage va effectuer son travail de comparaison de routes dans l’ordre...

Autres données de navigation

Il reste encore deux moyens additionnels de passer des données liées au routage. Angular offre la possibilité d’utiliser les propriétés data et state pour transmettre des informations de manière plus ciblée et adaptée à différents scénarios. Ces mécanismes sont moins communément utilisés car assez spécifiques, voyons cela ensemble.

Lorsque l’on crée une route, on peut définir une propriété data contenant des informations statiques. Cela peut être vu comme une configuration personnelle de la route, qui pourra être récupérée et lue par différents acteurs comme les composants, les guards, etc.

{ 
  path: '', 
  component: AboutPageComponent, 
  data: { 
    skipAuthorization: true, 
  }, 
}, 

Dans cet exemple, nous avons défini une propriété skipAuthorization qui pourra éventuellement être lue lors d’un guard, afin de préciser le comportement attendu.

La lecture de cette donnée se fait de la même manière que pour les paramètres communs : on peut y accéder depuis l’ActivatedRoute, et le snapshot via la propriété data.

Voici un exemple concret...

Introduction aux animations

Dans Angular, il existe un module pour créer et intégrer des animations visuelles, souvent utilisé lors de navigations entre les vues. La librairie @angular/animations repose sur l’ajout et la modification de styles CSS de manière fluide et contrôlée. Elle utilise une syntaxe spécifique qui facilite la définition des animations à travers des triggers, des transitions et des animations.

La transition entre deux états (par exemple, lorsque vous naviguez d’une route à une autre) est définie à l’aide de la fonction trigger(), qui contrôle les changements de styles d’un élément. Vous pouvez jouer sur plusieurs aspects des éléments, comme l’opacité, la position ou encore la transformation. Les animations peuvent être exécutées séquentiellement ou en parallèle, en fonction des besoins de l’application.

De plus, Angular expose des événements d’animation tels que @animation.start et @animation.done, qui permettent de déclencher des actions lorsque l’animation démarre ou se termine. Ces événements permettent une gestion plus fine des comportements asynchrones pendant les transitions.

1. Ajouter une première animation

Avant d’entrer dans les détails du fonctionnement des animations, commençons par ajouter ensemble une première transition simple dans notre application. L’objectif ici est de vous permettre de voir rapidement le résultat visuel, sans vous préoccuper pour le moment des concepts techniques ou de la structure interne. Suivez simplement les étapes pour ajouter cette animation, et une fois que vous aurez vu l’effet en action, nous reviendrons sur les explications détaillées.

 En tout premier lieu, si le package @angular/animations n’est pas déjà installé, vous pouvez l’ajouter manuellement grâce à la commande :

ng add @angular/animations 

 Puis activez les animations au niveau de la configuration globale, en ajoutant provideAnimations() dans la liste des providers.

Maintenant, nous allons créer un fichier transitions.ts, qui contiendra une animation avec un effet de glisse horizontale défini comme suit :

import { ...

Projet fil rouge

Cette fois nous allons scinder notre application en pages, afin d’avoir une page principale pour le tableau et une page réservée aux administrateurs. Afin de mettre en place ce que l’on a vu dans le chapitre, la partie administrateur sera donc protégée et chargée de manière différée. Cet exercice sera plutôt court pour se concentrer sur la mise en situation uniquement, sans ajouter de contenu particulier dans la section d’administrateur.

1. Prérequis

Encore une fois, il faut mettre à jour l’API. Si vous utilisez Mirage JS, vous pouvez directement récupérer la nouvelle version sur la branche correspondant à ce chapitre. Sinon, voilà le besoin :

  • Création d’un ticket :

  • la réponse devient : { ticket: Ticket }.

  • Édition d’un ticket :

  • requête HTTP PATCH sur "/api/board/ticket ",

  • body de type :

{ 
  ticket: {  
    id:string,  
    title:string,description:string,  
    type: TicketType,  
    assignee?: string  
  } 
} 
  • réponse : { ticket: Ticket }.

  • Récupération d’un ticket par identifiant :

  • requête HTTP GET sur "/api/board/ticket/:id ",

  • réponse : { ticket: Ticket }.

Avant de commencer, on va modifier le code actuel pour s’adapter aux nouvelles API :

Tout d’abord, modifions le modèle CreateTicketResponse pour être réutilisable par d’autres opérations :

export type TicketResponse = { ticket: Ticket }; 

Le service BoardService nécessite donc une mise à jour. Ajustez la méthode de création d’un ticket pour accepter un modèle de ticket en paramètre, en plus de l’identifiant de colonne. Puis ajoutez la fonction d’édition suivant la même forme :

createTicket(modele: TicketEditionCreation, columnId: string) { 
  return this.http.post<TicketResponse>( 
    `/api/board/ticket/${columnId}`, 
    { 
      ticket: modele, 
    } ...

Conclusion

Dans ce chapitre, nous avons exploré le système de navigation dans Angular, essentiel pour structurer une application en pages distinctes. Nous avons vu comment configurer les routes, naviguer entre les vues, gérer les paramètres d’URL via queryParams et les routes dynamiques, et optimiser le chargement avec le lazy loading pour les modules comme pour les composants standalone. Les guards, tels que CanActivate et Resolve, nous ont permis de sécuriser l’accès aux pages et de préparer les données nécessaires avant leur affichage. Enfin, l’introduction aux animations a montré comment enrichir l’expérience utilisateur grâce aux transitions et effets visuels entre les vues.

Dans l’exercice pratique, nous avons intégré ces concepts pour améliorer notre application Kanban. Nous avons défini les routes principales, ajouté une section lazy-loaded dédiée à l’administration, et finalisé la page de détails des tickets, qui récupère désormais dynamiquement ses informations depuis les paramètres de la route.

Le code complet de cet exercice est disponible sur GitHub : https://github.com/KevinAlbrecht/angular-eni/tree/chapitre-9. Dans le prochain chapitre, nous aborderons un sujet d’architecture : la gestion d’état. Nous découvrirons...