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 :
-
un chemin path
- il peut contenir éventuellemt des paramètres introduits par le caractère :
- le chemin chaîne vide représente le chemin par défaut (page d'accueil) de l'application
- le chemin joker ** est le chemin de dernier ressort suivi lorsque l'URL n'indique aucun autre chemin valide ; on le fait pointer généralement vers un composant indiquant une erreur
- les chemins sont testés par rapport à l'URL dans leur ordre de spécification (le premier chemin validant l'URL est utilisé)
- un composant component qui est le composant qui sera employé lorsque l'on naviguera vers le chemin indiqué
- une spécification de redirection redirectTo afin de rediriger vers un autre chemin (dans ce cas, on indique pas de composant)
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'); ... } }