Le moderne applicazioni Web basate sul modello SPA (Single Page Application) non possono fare a meno del meccanismo che consente all'utente di navigare tra una view e l'altra: il routing.
L'approccio proposto da Angular 2 per creare route e navigare tra le view è abbastanza semplice. Esso consente di effettuare una mappatura tra URL, componenti che fanno parte di un'applicazione e view in maniera lineare ed efficace.
Base, unificare route e url
Facendo riferimento all'applicazione che stiamo realizzando nel corso di questa guida, immaginiamo di voler aggiungere una barra di navigazione che consenta di passare dalla visualizzazione dell'elenco degli articoli a quella del modulo di inserimento di un nuovo articolo, come mostrato dalla seguente immagine:
Prima di includere il routing nella nostra applicazione dobbiamo verificare la presenza dell'elemento <base> nella pagina HTML che rappresenta il punto di ingresso dell'app. Tipicamente si tratta della pagina index.html
, in cui va inserito il seguente markup nella sezione <head>
:
<head>
<base href="/">
...
</head>
Questo piccolo particolare è molto importante, in quanto consente di abilitare lo stile HTML5 degli URL, cioè l'uso di URL per identificare le view (le route) identici a quelli utilizzati per inviare richieste ai server. In altre parole, possiamo identificare una view tramite un URL del tipo:
http://www.miaApp.com/main/miaView
senza bisogno di utilizzare l'hash (#) come nelle applicazioni Angular 1.x.
Se abbiamo utilizzato Angular CLI per creare la struttura di base dell'applicazione, l'HTML della pagina iniziale contiene già l'elemento <base>
correttamente configurato.
È tuttavia possibile utilizzare il vecchio approccio che fa uso dell'hash configurando opportunamente il routing, ma l'impostazione predefinita di Angular 2 prevede l'utilizzo degli URL in stile HTML5.
Introdurre il routing nell'app
Una volta sicuri di poter applicare lo stile di routing predefinito, dobbiamo fare un lavoro preliminare per ristrutturare la nostra applicazione. Spostiamo la logica per la visualizzazione dell'elenco degli articoli in un altro componente: ArticoloListaComponent:
import { Component} from '@angular/core';
import {ArticoliService} from '../articoli.service'
@Component({
selector: 'app-articolo-lista',
templateUrl: './articolo-lista.component.html',
styleUrls: ['./articolo-lista.component.css'],
providers: [ArticoliService]
})
export class ArticoloListaComponent {
elencoArticoli;
constructor(private articoliService: ArticoliService) {
articoliService.getArticoli()
.subscribe(result => {
this.elencoArticoli = result;
});
}
}
Questo componente avrà associato il seguente template HTML contenuto nel file articolo-lista.component.html
:
<ul>
<li *ngFor="let articolo of elencoArticoli">
<b>{{articolo.titolo}}</b> di {{articolo.autore}}
</li>
</ul>
Abbiamo semplicemente spostato il codice che prima era incluso in AppComponent
. Questo spostamento si rende necessario perché l'intenzione di aggiungere una barra di navigazione modifica la struttura gerarchica dei componenti della nostra applicazione. Infatti, la nuova gerarchia prevede che il root component AppComponent
possa avere più figli visualizzati in modo esclusivo. In altre parole, l'interazione dell'utente con il root component visualizzerà l'elenco degli articoli oppure la maschera di inserimento di un nuovo articolo, ma mai entrambe le view.
A questo punto siamo pronti per introdurre il routing nella nostra applicazione. Per prima cosa modifichiamo il modulo principale come mostrato di seguito:
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { RouterModule } from '@angularouter';
...
@NgModule({
imports: [
RouterModule.forRoot([
{
path: '',
component: ArticoloListaComponent
},
{
path: 'nuovoArticolo',
component: ArticoloFormComponent
}
]),
...
],
declarations: [
AppComponent,
...
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Notiamo che è stata aggiunta l'importazione del componente RouterModule dal modulo @angularouter. Questo componente viene utilizzato per dichiarare a livello di applicazione la mappatura tra le "rotte" previste dalla nostra applicazione e i rispettivi componenti:
RouterModule.forRoot([
{
path: '',
component: ArticoloListaComponent
},
{
path: 'nuovoArticolo',
component: ArticoloFormComponent
}
])
Il metodo forRoot() permette di associare l'array di route
passato come argomento, alla root dell'applicazione. Esso esegue la navigazione iniziale partendo dall'URL corrente del browser.
I due oggetti contenuti nell'array delle route
indicano rispettivamente che l'URL iniziale associato alla nostra applicazione (/
) viene mappato sul componente ArticoloListaComponent
, mentre l'URL /nuovoArticolo
viene mappato sul componente ArticoloFormComponent
.
Naturalmente allo stato attuale della nostra implementazione non noteremo nulla di diverso rispetto a prima, dal momento che abbiamo dichiarato come mappare URL a componenti ma non abbiamo indicato dove questi componenti vanno visualizzati.
Per far questo utilizzeremo il router outlet, una direttiva messa a disposizione dal RouterModule che consente di indicare dove un componente deve essere renderizzato.
Utilizzeremo il router outlet in combinazione dei router link, altra direttiva che consente di creare link che abilitano la navigazione tra le view dichiarate tramite il routing. Modifichiamo il template HTML del componente AppComponent
come mostrato di seguito:
<h1>
{{title}}
</h1>
<nav>
<a routerLink="/">Elenco articoli</a>
<a routerLink="/nuovoArticolo">Aggiungi articolo</a>
<router-outlet><outer-outlet>
</nav>
Notiamo l'uso dell'attributo routerLink all'interno dell'elemento <a>
che specifica l'URL da prendere in considerazione per la navigazione tra le view. L'elemento <router-outlet> è il contenitore all'interno del quale verranno visualizzare le view corrispondenti alla route
corrente.
Dal momento che alla route /
abbiamo associato il componente ArticoloListaComponent
, al primo accesso alla nostra applicazione vedremo l'elenco degli articoli disponibili.
Quando l'utente clicca sul link corrispondente alla voce Aggiungi articolo, l'area prima occupata dall'elenco degli articoli verrà utilizzata per visualizzare il modulo di inserimento di un nuovo articolo, come mostra la seguente immagine: