1 of 19

Angular - Routing

Diseño para todys

2 of 19

Single Page Application revisited

¿Por qué “Single Page”? Porque inicialmente vamos a cargar una única página de nuestra app (es el index.html)

3 of 19

Single Page Application revisited

El primer pedido de nuestro navegador al server trae además otros archivos necesarios para levantar la app: css, js compilados, etc.

4 of 19

¿Cómo cambiar de página?

Aquí es donde aparece el concepto de routing.

5 of 19

El mecanismo de ruteo de Angular

Es muy similar en otras tecnologías, consiste en poder asociar una ruta particular con un componente

clientes

ClientesComponent

clientes/:id

EditarClienteComponent

**

PageNotFoundComponent

IMPORTANTE, que no empiece con /

6 of 19

Definiendo un proyecto con routing

Solo debemos agregar esa opción al crear un nuevo proyecto:

Esto resuelve de antemano algunas cosas.

ng new proyecto-angular --routing

7 of 19

Proyecto con routing: 1) app-routes.ts

En este archivo vamos a definir las rutas y a asociarlo con componentes de Angular:

export const routes: Routes = [

{ path: 'listaTareas', component: ListaTareasComponent },

{ path: 'editarTarea/:id', component: EditarTareaComponent },

{ path: '**', redirectTo: '/listaTareas', pathMatch: 'full' },

]

​

Las rutas aceptan wildcards.

Se asocian a componentes o redireccionan a otras rutas.

Es importante el orden, donde primero aparezca la ruta más específica

8 of 19

Proyecto con routing: 2) app.config.ts

En este archivo vamos a definir las rutas y a asociarlo con componentes de Angular:

import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'

import { provideRouter } from '@angular/router'

​

import { routes } from './app.routes'

import { provideHttpClient } from '@angular/common/http'

​

export const appConfig: ApplicationConfig = {

providers: [

provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes),

provideHttpClient()

]

}

No hay mucho para comentar, el provider inyecta la dependencia

9 of 19

Proyecto con routing: 3) app.component.ts

En nuestro módulo principal debemos declarar los componentes a los que queremos navegar y también importar el componente definido en el archivo app-routing.module:

import { Component } from '@angular/core'

import { RouterOutlet } from '@angular/router'

​

@Component({

selector: 'app-root',

standalone: true,

imports: [RouterOutlet],

templateUrl: './app.component.html',

styleUrl: './app.component.css'

})

export class AppComponent {

title = 'app'

}

10 of 19

Proyecto con routing: 4) cambios al app.component.html

Separamos la parte estática y la dinámica, determinada por la ruta de la aplicación:

<div style="text-align:center">

<br>

<h1>

Tareas - Routing

<small>Angular</small>

</h1>

<br>

</div>

​

<router-outlet></router-outlet>

​

parte estática

parte dinámica

11 of 19

Proyecto con routing: 4) cambios al app.component.html

​

Eso lo podemos ver cuando levantamos la aplicación, el router-outlet es un contenedor que va cambiando dinámicamente:

Tip 1: ver los tags que se crean como hermano de router-outlet.

Tip 2: manipular el DOM mediante document.getElementByTagName(...)

12 of 19

Cómo navegar a otra página desde la vista html

Podemos utilizar el binding routerLink, que nos permite editar una tarea específica:

Recordemos que la ruta editarTarea necesita dentro de la URL el id:

Los corchetes solo son necesarios para evaluar código typescript, de lo contrario podés utilizarlo en forma directa:

@for (tarea of tareas | ... ; track tarea; ...) { <tr [routerLink]="['/editarTarea, tarea.id]">

export const routes: Routes = [

{ path: 'listaTareas', component: ListaTareasComponent },

{ path: 'editarTarea/:id', component: EditarTareaComponent },

{ path: '**', redirectTo: '/listaTareas', pathMatch: 'full' },

]

​

<nav>

<a class="button" routerLink="/crisis-list">Crisis Center</a> |

<a class="button" routerLink="/heroes-list">Heroes</a>

</nav>

13 of 19

Cómo navegar a otra página desde la vista html (II)

De esa manera se construye la url final: http://localhost:4200/editarTarea/1

14 of 19

ActivatedRoute para poder capturar parámetros

El componente principal debe registrarse como interesado en recibir los parámetros desde la URL. Así puede capturar el valor del identificador de la tarea:

export class EditarTareaComponent implements OnInit {

tarea!: Tarea

descripcionTarea!: string

​

constructor(private tareaService: TareaService, private router: Router,

private route: ActivatedRoute) {}

​

ngOnInit() {

this.route.params.subscribe((editarTareaParameters) => {

const tarea = this.tareaService.getTareaById(editarTareaParameters.id)

​

{ path: 'editarTarea/:id', component: EditarTareaComponent },

id es el nombre del parámetro como lo definimos en la ruta

15 of 19

Navegando en forma programática

Podemos disparar la navegación desde nuestro componente si le inyectamos previamente el router y enviamos el mensaje navigate:

export class EditarTareaComponent implements OnInit {

​

constructor(private tareaService: TareaService, private router: Router,

private route: ActivatedRoute) { ...

navegarAHome() {

this.router.navigate(['/listaTareas'])

}

​

siempre trabajamos con el path

​

otra variante aquí abajo redireccionaría a “la siguiente tarea”...

this.router.navigate(['/editarTarea', this.tarea.id + 1])

16 of 19

Navegación con query parameters

En lugar de pasar el id como parámetro podemos generar un query param que construye una ruta como un par clave/valor

<a [routerLink]="['product-list']" [queryParams]="{ page: 99 }">Go to Page 99</a>v

ngOnInit() {

this.sub = this.route.paramMap.subscribe(params => { this.page = +params['page'] || 0 })

}

​

ngOnDestroy() {

this.sub.unsubscribe();

}

​

nextPage() {

this.router.navigate(['product-list'], { queryParams: { page: this.page + 1 } });

}

17 of 19

Base href en el index.html

Como parte del checklist hay que verificar que dentro del header de tu index.html principal tengas esta configuración:

Esto habilita los “deep links” o forma de acceder a un componente directamente.

<!doctype html>

<html lang="en">

<head>

...

<base href="/">

18 of 19

Base href en el index.html

Y para que funcionen tus tests de frontend vas a necesitar agregar esa configuración a TestBed:

describe('ListaTareasComponent', () => {

...

​

beforeEach(waitForAsync(() => {

TestBed.configureTestingModule({

declarations: [ ... ],

imports: [

FormsModule,

RouterModule.forRoot(routes)

],

providers: [

{ provide: APP_BASE_HREF, useValue: '/' }

representa el

<base href="/">

19 of 19

¡Gracias!