Mise en Place du Routing

1. Tag base

Avant toute chose, il est nécessaire d'ajoute le tag base au head du fichier index.html de l'application :

<!doctype html>
<html>
    <head>
        <base href="/">
        ...
    </head>
    <body>
        ...
    </body>
</html>

Ce tag indique la base du path à partir de laquelle le "Routing" Angular rentre en jeu.

Cette valeur est généralement personnalisé dans le cas où plusieurs applications Angular sont hébergées sur un même nom de domaine mais avec des paths différents.

2. Configuration

Configuration du "Routing"

La configuration du "Routing" est transmise au module RouterModule lors de son import par le "root module" AppModule.

Par bonne pratique, il est recommandé de placer cette configuration dans un module dédié AppRoutingModule importé par le "root module" AppModule.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

export const appRouteList: Routes = [
    {
        path: 'landing',
        component: LandingViewComponent
    },
    {
        path: 'search',
        component: BookSearchViewComponent
    },
    {
        path: '**',
        redirectTo: 'landing'
    }
];

@NgModule({
    exports: [
        RouterModule
    ],
    imports: [
        RouterModule.forRoot(appRouteList)
    ]
})
export class AppRoutingModule {
}

`` est une "wildcard"** qui "match" toutes les urls (sauf celles qui ont "match" les routes précédentes).

Il faut donc faire attention à l'ordre des "routes".

Configuration d'une "Route" avec Paramètres

Le path d'une "route" peut définir des paramètres obligatoires grâce au préfixe :.

export const appRouteList: Routes = [
    ...,
    {
        path: 'books/:bookId',
        component: BookDetailViewComponent
    },
    ...
];

Configuration de l'Hébergement

Pour le bon fonctionnement du "Routing", il est important d'implémenter une règle de "rewrite" sur votre plateforme d'hébergement afin que toutes les "routes" renvoient le même fichier index.html produit dans le dossier dist lors du "build" (yarn build).

Autrement, en accédant directement à une "route" de l'application, l'utilisateur obtiendrait une erreur 404.

3. <router-outlet>

La configuration du "Routing" permet de définir quel composant afficher en fonction de la route mais cela n'indique pas à Angular où injecter le composant dans la page.

Pour indiquer l'emplacement d'insertion du composant, il faut utiliser la directive <router-outlet> directement dans le "root component" AppComponent (ou dans un "child component" dédié, e.g. HomeLayoutComponent).

<header>
...
</header>
<router-outlet></router-outlet>
<footer>
...
</footer>

En fonction de la "route" visitée, le composant associé sera alors injecté en dessous du tag router-outlet (et non à l'intérieur ou à la place du tag contrairement à ce que l'on pourrait supposer).

4. Création de liens

En utilisant des liens natifs <a href="/search">, le "browser" va produire une requête HTTP GET vers le serveur et recharger toute l'application.

Pour éviter ce problème, le module de "Routing" Angular fournit la directive routerLink qui permet d'intercepter l'événement click sur les liens et de changer de "route" sans recharger toute l'application.

<a routerLink="/search">Search</a>

La directive routerLink génère tout de même l'attribut href pour faciliter la compréhension de la page par les "browsers" ou "moteurs de recherche". Cela permet par exemple, d'ouvrir un lien dans une nouvelle fenêtre grâce au menu contextuel ou encore copier le lien d'une "route".

Construction Dynamique

La "route" peut être construite dynamiquement et passée à l'Input routerLink.

this.route = '/search';
this.routeName = 'Search';
<a [routerLink]="route">{{ routeName }}</a>

Construction avec Paramètres

La "route" /books/123 peut être construite avec des paramètres :

<a [routerLink]="['/books', book.id]">{{ routeName }}</a>

book.id = '123'.

Il est également possible de passer des paramètres optionnels par "query string" via l'Input queryParams.

<a
    routerLink="'/search"
    [queryParams]="{keywords: 'eXtreme Programming'}">eXtreme Programming Books</a>

5. Accès aux Paramètres

Le service ActivatedRoute décrit l'état actuel du "router". Il permet au composant associé à la "route" de récupérer les paramètres via les propriétés paramMap et queryParamMap.

Les propriétés paramMap et queryParamMap sont des Observables car par optimisation, en naviguant vers la même route mais avec des paramètres différents (e.g. /books/123 => /books/456), Angular ne recharge pas le composant mais propage les nouveaux paramètres via ces Observables.

export class BookDetailViewComponent {

    book$: Observable<Book>;

    constructor(private _activatedRoute: ActivatedRoute,
                private _bookRepository: BookRepository) {

        this.book$ = this._activatedRoute.paramMap
            .pipe(
                map(paramMap => paramMap.get('bookId')),
                switchMap(bookId => this._bookRepository.getBook(bookId))
            );

    }

}

Pour simplifier la récupération des paramètres, il est également possible d'utiliser la propriété snapshot qui contient l'état actuel de la route (e.g. : snapshot.paramMap.get('bookId')). Le risque dans ce cas est de ne pas mettre à jour la vue en cas de navigation vers la même route avec des paramètres différents.

6. Router Service

Le Router est le service principal du "Routing". Il permet de :

  • déclencher la navigation via la méthode navigate, this._router.navigate(['/books', bookId], {queryParams: {}})

  • suivre les événements de navigation via l'Observable router.events,

  • construire et parser les urls de "Routing",

  • vérifier si une "Route" est actuellement visitée,

  • ...

Dernière mise à jour