viernes, 16 de diciembre de 2016

Angular 2. Entrega 14. Aplicaciones multipágina: Router

Seguimos con las magníficas explicaciones de nuestro apreciado amigo Micael Gallego.

"Las webs SPA (single page application) pueden tener varias pantallas simulando la navegación por diferentes páginas".

Imaginemos una página con un índice que accede a otra con el contenido.

1. La página (componente) principal

El componente principal (app-root) tiene:

  1. Una parte fija (cabecera, footer)
  2. Una parte variable cuyo contenido depende  de la URL (<router-outlet>)

import { Component } from '@angular/core';


@Component ({
  selector: 'app-root',
  template: `
    <h1 class="title">Library</h1>
    <router-outlet></router-outlet> <!-- Zona que cambia con la URL--> 
    ´
})
export class AppComponent {}


2. Configuración de las rutas en app.routing.ts 

Hay un componente app-routing.ts donde se definen que componentes se muestran para cada URL

Hay que destacar del código que mostraremos:

1. Las 3 formas distintas de enrutar que hay en appRoutes, donde se indica para cada ruta que componente cargamos. La ruta puede ser fijas( 'books') o con un "placeholder" que se indica con 2 puntos ('books/:id'). También se puede "redireccionar a otra ruta" la cual hemos definido antes con el componente asociado. Por cierto, en este último caso hay que indicar pathMatch:'full'

2. El método de clase RouteModule.forRoot(appRoutes)que mete las rutas en el ngModule. Pero el estilo de meterlas es exportándolas con dicha clase

import {Routes, RouterModule } from '@angular/router';
import {BookListComponent } from './book-list.component';
import {BookDetailComponent } from './book-detail.component';

const appRoutes = [
  { path: 'books/:id', component: BookDetailComponent },
  { path: 'books', component: BookDetailComponent },
  { path: '', redirectTo: 'books', pathMatch:'full' }
]
export const routing = RouteModule.forRoot(appRoutes);

Estas rutas son globales a toda la aplicación, pero hay mucha tela ya que se pueden hacer rutas por componente, carga perezosa (lazy loading)

3. Definición en el app.module.ts 

Hay que importar el routing exportado del app.routing.ts, tanto en la parte import como en imports. Si nos fijamos bien lo estamos dando de alta como un módulo.

...
import {routing} from './app,routing';

@NgModule ({
  declarations: [AppComponent, BookDetailComponent, BookListComponent],
  imports: [BrowserModule, FormsModule, HttpModule, JsonModule, routing],
})
export class AppModule {}


4. ¿Como navegar de un sitio a otro?

Se utilizan  links especiales(evitando href) para navegar dentro de la aplicación web (código html) ([routerLink]) (que es un array de strings), que evitan la recarga global.

Este es book-list.component,ts o sea la LISTA de libros. Cuando hacemos click sobre los elementos comprendidos dentro del routerLink. El routerLink puede incluir la ruta y los parámetros, en ese caso el parámetro es book.id
...
@Component({
  template: `
    <h2>BOOKS</h2>
    <ul>
      <li *ngFor="let book of books">
        <!-- La ruta se puede indicar como un string o un array de estrings si hay parametros -->
        <a [routerLink]="['/book',book.id]">
          {{book.id}}-{{book.title}} <!-- tiene el identificador y titulo del libro -->
        </a>
      <li>
    </ul>
  `
})
export class BookListComponent {
  books: Book[];
  constructor (service: BookService) {
    this.books = service.getBooks();
  }
}

5. Acceder al libro concreto a visualizar en el componente detail

Para ello, tenemos que acceder a los servicios de Router y ActivatedRoute, y por supuesto a los servicios que nos den la información del libro (BookService).
Para obtener el id del libro, accedemos al método snapshot.params['id'] del objeto de la clase ActivatedRoute para acceder a los parámetros.

No olvidarse de hacer los import

Con el botón ejecutamos la función getBooks que utiliza a Router para volver a '/books' con el metodo navigate (podriamos acceder a cualquier otra direccion disponible en el route)
O sea navegamos con un objeto de la clase Router

...
import { Router, ActivateRouter } from '@angular/router'
@Component({
  template: `<h2>{{book.title}}</h2>
    <div><label>Id: </label>{{book.id}}</div>
    <div><label>Description:</label></div>
<p><button (click)="gotoBooks()">Back</button></p>
})
export class BookDetailComponent {
  book: Book;
  constructor (private router:Router, activatedRoute:ActivatedRoute, bookService:BookService) {
    let id=activatedRoute.snapshot.params['id'];
    this.book=book-service.getBook(id);
  }
  getBooks() { this.router.navigate (['/books']); }
}

6. Las rutas ' ' y '**'

Estas rutas son para indicar la ruta por omisión y la ruta cuando se inidica desde la aplicación una ruta que no existe. Por ejemplo http://localhost:3030 apuntaria a la route indicada por ' ' ,mientras que si nuestra  aplicación hace un this.router.navigate (['/direccion_inexistente']), cogería la route indicada pro '**', evitando lanzar una excepción de ruta no encontrada

const appRoutes = [
  { path: 'books/:id', component: BookDetailComponent },
  { path: 'books', component: BookDetailComponent },
  { path: '', redirectTo: 'books', pathMatch:'full' },
  { path: '**', component: PageNotComponent  }
]

No hay comentarios :

Publicar un comentario