image/svg+xml $ $ ing$ ing$ ces$ ces$ Res Res ea ea Res->ea ou ou Res->ou r r ea->r ch ch ea->ch r->ces$ r->ch ch->$ ch->ing$ T T T->ea ou->r

Introduction

Le concept de routage est utilisé par les frameworks de développement de serveur web afin d'associer à une adresse de ressource le gestionnaire de cette ressource. Le serveur peut ainsi instancier les gestionnaires nécessaires et leur communiquer des arguments indiqués dans l'URL de la ressource demandée.

Une application Angular est exécutée par le client et se compose d'une unique page HTML accompagnée de fichiers JavaScript. D'un point de vue du serveur, elle est donc accessible depuis une URL unique (son fichier HTML), par exemple https://example.com/angularApp/index.html. Avec le mécanisme de routage intégré à Angular, on pourrait utiliser une URL du type https://example.com/angularApp/component1/element. Il est donc nécessaire que le serveur web serve toujours la page index.html quel que soit le chemin complémentaire indiqué après le répertoire angularApp : cela nécessite une configuration spécifique du serveur web. Il sera de la responsabilité de l'application Angular d'analyser l'URL après angularApp afin de router vers le bon composant.

Si le serveur web n'est pas configurable, il est toutefois possible d'ajouter dans l'URL de la page un fragment introduit par # représentant la partie de l'URL propre à l'application Angular et qui ne sera accessible qu'au client (pas de communication au serveur web).

Des informations complètes sur le module de routage sont disponibles dans la documentation Angular.

Spécification des routes

Angular propose un module de routage que l'on peut activer dans le fichier app.module.ts. On lui communique un tableau de routes. Une route contient :

Voici un exemple de fichier app.module.ts contenant des routes vers des composants :

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule,  ReactiveFormsModule }   from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule, Routes } from '@angular/router';

import { AppComponent } from './app.component';
import { HelloWorldComponent } from './hello-world/hello-world.component';
import { MutabilityComponent } from './mutability/mutability.component';
import { PersonComponent } from './person/person.component';
import { CoupleComponent } from './couple/couple.component';
import { DivmoveComponent } from './divmove/divmove.component';
import { SlotMachineComponent } from './slot-machine/slot-machine.component';
import { CasinoComponent } from './casino/casino.component';
import { CurrencyConverterComponent } from './currency-converter/currency-converter.component';
import { KeypadComponent } from './keypad/keypad.component';
import { TimestampComponent } from './timestamp/timestamp.component';
import { BitcoinTickerComponent } from './bitcoin-ticker/bitcoin-ticker.component';
import { PictureViewerComponent } from './picture-viewer/picture-viewer.component';
import { KeypadWrapperComponent } from './keypad-wrapper/keypad-wrapper.component';
import { DirectoryComponent } from './directory/directory.component';

const appRoutes: Routes = [
  { path: 'hello-world', component: HelloWorldComponent },
  { path: 'mutability',  component: MutabilityComponent },
  { path: 'couple', component: CoupleComponent },
  { path: 'divmove', component: DivmoveComponent },
  { path: 'casino', component: CasinoComponent },
  { path: 'currency-converter', component: CurrencyConverterComponent},
  { path: 'keypad', component: KeypadWrapperComponent },
  { path: 'directory', component: DirectoryComponent },
  { path: 'timestamp', component: TimestampComponent },
  { path: 'bitcoin', component: BitcoinTickerComponent },
  { path: 'picture/:width/:height', component: PictureViewerComponent }
];

@NgModule({
  declarations: [
    AppComponent,
    HelloWorldComponent,
    MutabilityComponent,
    PersonComponent,
    CoupleComponent,
    DivmoveComponent,
    SlotMachineComponent,
    CasinoComponent,
    CurrencyConverterComponent,
    KeypadComponent,
    TimestampComponent,
    BitcoinTickerComponent,
    PictureViewerComponent,
    KeypadWrapperComponent,
    DirectoryComponent
  ],
  imports: [
    BrowserModule,
    FormsModule, ReactiveFormsModule,
    HttpClientModule,
    RouterModule.forRoot(appRoutes, { enableTracing: true, useHash: true, relativeLinkResolution: 'legacy' })
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Si le serveur web n'est pas configuré pour rediriger les URL Angular vers la page HTML de l'application, on peut utiliser l'option useHash pour indiquer le chemin de navigation Angular dans le fragment après un # :

RouterModule.forRoot(routes, {useHash: true})

Directive RouterOutlet

La directive RouterOutlet est utilisée dans le template du composant principal app afin d'indiquer l'endroit où le composant routé doit être affiché :

<router-outlet></router-outlet>

On ajoute également sur le template des liens de routage permettant de changer le composant affiché sur l'outlet :

<nav>
	<a routerLink="/component1" routerLinkActive="active">Composant 1</a>
	<a routerLink="/component2" routerLinkActive="active">Composant 2</a>
	...
</nav>

Voici un exemple complet de template contenant des liens de navigation ainsi que le router outlet :

<h1>Angular demonstration app</h1>

<nav>
	<a routerLink="/hello-world" routerLinkActive="active">Hello world!</a> -
	<a routerLink="/mutability" routerLinkActive="active">Mutability test</a> -
	<a routerLink="/couple" routerLinkActive="active">Couple exchange</a> -
	<a routerLink="/divmove" routerLinkActive="active">Moving mouse into a div</a> -
	<a routerLink="/casino" routerLinkActive="active">Casino</a> -
	<a routerLink="/currency-converter" routerLinkActive="active">Currency conversion</a> -
	<a routerLink="/keypad" routerLinkActive="active">Keypad</a> -
	<a routerLink="/directory" routerLinkActive="active">Directory</a> -
	<a routerLink="/timestamp" routerLinkActive="active">Timestamp update</a> -
	<a routerLink="/bitcoin" routerLinkActive="active">Bitcoin ticker</a> -
	<a routerLink="/picture/300/300" routerLinkActive="active">Image viewer (300x300)</a>
</nav>

<div class="routerOutlet">
	<router-outlet></router-outlet>
</div>

Accès au routage depuis un composant

Un composant peut être affiché dans le router outlet depuis une URL. Le chemin peut contenir des paramètres que l'on peut récupérer. Ainsi si nous avons une route du type :

[ { path: 'picture/:width/:height',        component: PictureFetcherComponent }

il est nécessaire de pouvoir récupérer les paramètres width et height dans le composant. Malheureusement ce n'est pas encore possible automatiquement à l'aide de champ marqués avec l'annotation @Input(). Il faut avoir accès à la route courant ainsi qu'au routeur :

import { Router, ActivatedRoute, ParamMap } from '@angular/router';

...
class PictureFetcherComponent implements NgOnInit {
	...
	
	constructor(
		private route: ActivatedRoute,
		private router: Router,
		...) {}
		
	ngOnInit() {
		let width = this.route.snapshot.paramMap.get('width');
		let height = this.route.snapshot.paramMap.get('height');
		...
	}
}