8 - Router

Router

Si hay algo a lo que se le dio mucha vida y lineas de código , y reescritura... Sin NINGUNA duda fue el Router... Angular paso por 3 versiones de router, mas una de NgRX, para poder tener la que tenemos ahora ... de hecho si lo recuerdan Angular en Marzo del 2017 pasa de la version 2.x.x a la 4... para mantener un "hilo" con el router...

Ahora si, luego de tantas "idas y vueltas" con el router y de aprender unos cuantos, yo me habia quedado con el router de NgRX, tenia componentes reactivos y para todo se utilizaban observables... era super entretenido... pero con la version del router final, que creo Victor Savkin ( @victorsavkin ), cambiaron muchas cossa, y hizo que vuelva a darle un vistazo al "nuevo" router, que estaba dentro de la capa del "core" ( lo pongo entre comillas porque esta en otro paquete, mas alla que es como parte del core) entonces encontre que con el "nuevo" router se podían hacer muchas mas cosas que simplemente "si cambias a estar url => carga este componente".

Realmente pareceria poco decir que al cambiar la URL cambia el Componente, entre cada una de las cosas que hace el router para ver sus funcionalidades un poco mas a fondo.

Entendiendo los pasos del router:

  • El router de Angular toma la URL y "ejecuta" las siguientes "funcionalidades":

    1. Aplica la redirección

    2. Reconoce el estado del router

    3. Ejecuta "guards" y resuelve datos

    4. Activa todos los componentes necesarios

    5. Administra la navegación para un futuro cambio.

SI!!! hace estas cosas cada vez que cambiamos una URL interna ( dentro de la aplicación) ... Claro que uno "tiene idea" de lo que pasa .. pero no sabe todo lo que va ejecutando por atras el router cada vez que cambiamos la url... por lo general nosotros no nos preocupamos por esto (esta bien) pero no me parece mal que se sepa. Recuerden que el proposito es que entiendan como funciona angular, al entender como funciona, van a poder programar mas comodos y entender rapidamente como resolver ese bug o como realizar esa feature que se acerca.

Formato de la URL:

/usuarios/10(popup:compose)

/usuarios/

/usuarios/10;open:true/tickets/resueltos

Como se puede ver, el router utiliza paréntesis para serializar segmentos secundarios (por ejemplo, popup: compose), la sintaxis de dos puntos para especificar la salida y la sintaxis '; parameter = value' (por ejemplo, open = true) para especificar parámetros específicos de ruta .

Configuración:

Lo primero que vamos a hacer cuando queramos programar nuestras funcionalidades dentro del router va a ser su configuración y lo primero ( siempre se puede ir modificando ) es crear nuestras rutas.

export const ROUTERCONFIG = [
    { path:'', pathMatch: 'full', redirectTo: '/home' },
    {path: 'home', component: HomeComponent },
    {
        path: ':id',
        children: [
            { path: '', component: UsuariosComponent },
            {
                path: ':id',
                component: UsuarioComponent,
                children: [

                    { path: 'tickets', component: TicketsComponent },

                    { path: 'tickets/:status', component: TicketComponent }
                ]
            }
        ]
    },
    {
        path: 'compose',
        component: ComposeTicketComponent,
        outlet: 'popup'
    },
    {
        path: 'tickets/:status',
        component: PopupTicketComponent,
        outlet: 'popup'
    }
];

Como funciona una redirección:

Redirección: Un redireccionamiento es una sustitución de una "parte" de la URL. Los redireccionamientos pueden ser locales o absolutos. Los redireccionamientos locales reemplazan una sola "parte" por una diferente. Los redireccionamientos absolutos reemplazan toda la URL. Los redireccionamientos son locales a menos que prefijemos una url con una barra.

Modificar URL: Cuando un usuario o función cambian la URL, el router obtiene la modificación, lo PRIMERO que hacer el router es modificar el texto de la URL para aplicar el funcionamiento de la redirección.

Reconocer el estado: para esto el router va a tener que reconocer la URL que acaba de modificar, entendiendo desde donde arranca y que contiene que "checkear" en la configuración si existe tal y que debe hacer ( o que debe hacer en el caso de que no exista) para esto deberiamos entender que es cada parte de las URLS (rutas).

Que es cada una de las "cosas" que tiene una URL para el router y para que las configuramos, para ello el Router hace un "forEach" ( recorre todos las posiblidades de las configuraciones del router cuando se modifica la url).

":id" => todo lo que contenga dos puntos adentro es un "segmento variable" , lo que quiere decir es que el router ahi sabe que puede venir algo directamente ( y que luego tiene que seguir haciendo match con lo que continua de la configuración)

Parametros fijos => son aquellos que estan "fijos" por ejemplo en nuestro caso ... luego de recibir :id esperamos que tenga un "tickets" o "ticket/:status" o sea que si viniera "tickets" seguramente seria un "listado" con todos los tickets... entonces el parametros "tickets" o "ticket" son fijos, y estos hacen que el router pueda entender para donde debe ir.

Si el camino tomado a través de la configuración no "consume" toda la URL, el router retrocede para intentar una ruta alternativa. Si es imposible emparejar toda la URL, la navegación fallará. Pero si funciona, se construirá el estado del enrutador que representa el estado futuro de la aplicación.

Router State: Un estado de enrutador consiste en rutas activadas. Y cada ruta activada puede estar asociada con un componente. Además, tenga en cuenta que siempre tenemos una ruta activada asociada con el componente raíz de la aplicación. O sea basicamente, son las rutas que existen y se pueden acceder, osea es la conexion entre la URL y el Componente, con la aclaracion que vamos a poder darle un componente a nuestra URL raiz.. que podria ser por ejemplo www.ejemplo.com o www.ejemplo.com/myAngularApp/

Ejecuta los "Guards": el router checkeara que el estado actual de la aplicación tiene "permisos" para poder pasar al siguiente estado... Esto lo hara con los Guards (con estos Guards podremos manejar los "permisos" de la navegación, se puede usar para seguridad, autorización o propositos de monitoreo entre otras cosas).

Resuelve la "data": ahora por ultimo lo que le queda es resolver los datos que obtiene

constructor(route: ActivatedRoute)

En nuestro constructor vamos a tener que inyectar ( si ! lo se, no lo vimos todavía, es justo el siguiente capítulo) el "ActivatedRouter" y con el vamos a poder obtener los parametros/datos enviados

this.tickets = route.data.pluck('tickets');

Activación del componente: ahora que ya ejecuto todo lo anterior esta en posición para activar el componente que necesita, para ello recordemos que ya creamos todo lo necesario para poder utilizarlo.

hasta aca todo muy lindo pero todo esto en donde se va a encontrar ?? donde se va a ejecutar ?

Bien, para poder ejecutar el router vamos a tener que hacer algunas cosas mas que simplemente tener un Array de objetos que entiende el router..

Para ello voy a explicar aquí en el codigo como hacer ...

Primero vamos a configurar bien nuestro "config":

/commos/router.ts

import { HomeComponent } from '../components/home/home.component';
import { UsuariosComponent } from '../components/usuarios/usuarios.component';
import { UsuarioComponent } from '../components/usuarios/usuario.component';
import { TicketsComponent } from '../components/tickets/tickets.component';
import { TicketComponent } from '../components/tickets/ticket.component';
import { ComposeTicketComponent } from '../components/tickets/compose.ticket.component';
import { PopupTicketComponent } from '../components/tickets/popup.ticket.component';

export const ROUTERCONFIG = [
    { path:'', pathMatch: 'full', redirectTo: '/home' },
    {path: 'home', component: HomeComponent },
    {
        path: ':id',
        children: [
            { path: '', component: UsuariosComponent },
            {
                path: ':id',
                component: UsuarioComponent,
                children: [

                    { path: 'tickets', component: TicketsComponent },

                    { path: 'tickets/:status', component: TicketComponent }
                ]
            }
        ]
    },
    {
    path: 'compose',
    component: ComposeTicketComponent,
    outlet: 'popup'
    },
    {
    path: 'tickets/:status',
    component: PopupTicketComponent,
    outlet: 'popup'
    }
];

Aquí como vimos tenemos la configuración, vamos a tener que importar los componentes para que lo podamos utilizar en nuestra config.

Por otro lado vamos a tener que configurar nuestros modulos, Angular Router, es una dependencia dentro de angular que esta "separada" dentro de las dependencias de core.. por lo tanto la vamos a llamar como @angular/router.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';

// components
import { HomeComponent } from './components/home/home.component';
import { UsuariosComponent } from './components/usuarios/usuarios.component';
import { UsuarioComponent } from './components/usuarios/usuario.component';
import { TicketsComponent } from './components/tickets/tickets.component';
import { TicketComponent } from './components/tickets/ticket.component';
import { ComposeTicketComponent } from './components/tickets/compose.ticket.component';
import { PopupTicketComponent } from './components/tickets/popup.ticket.component';


//router 
import { ROUTERCONFIG } from './commons/router';
import { RouterModule } from '@angular/router';

//directivas custom
import { TitleBlueDirective } from './directives/title.blue.directive';

@NgModule({
  declarations: [
    AppComponent,
    // directives
    TitleBlueDirective,
    // coponents
    HomeComponent,
    UsuariosComponent,
    UsuarioComponent,
    TicketsComponent,
    TicketComponent,
    ComposeTicketComponent,
    PopupTicketComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule.forRoot(ROUTERCONFIG)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Ahora si, ya importamos nuestro modulo , y con "forRoot" vamos a darle una configuración inicial, que es la que creamos anteriormente... lo que nos queda es crear los componentes, como son dummys todos, voy a mostrar donde muestra nuestro ruteador.

Para eso tenemos que tener algun lado donde se genere el mismo, el router corre bajo un tag, que en nuestro caso vamos a llamar dentro de nuestro componente principal:

app.component.html

<h1 [style.background]="'lime'" title-blue>
  {{title}}
</h1>
<router-outlet></router-outlet>

En este nuevo tag "router-outlet" vamos a poder ver los que cargue nuestro Router... entonces ya con todo esto, cuando arranquemos nuestra app, debería levantar el componente que utilizamos como Home ...

/components/home/home.component.ts

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

@Component({
    selector: 'home',
    template: '<h1> Home </h1>'
})
export class HomeComponent {}

Y como resultado tenemos:

Para ver todo el código pueden verlo en github, en el paso "router-01".

Last updated