Cómo utilizar los solucionadores de rutas con Angular Router
Introducción
Una forma de gestionar la recuperación y visualización de datos de una API es dirigir a un usuario a un componente y, luego, en ngOnInit
el enlace de ese componente, llamar a un método de un servicio para obtener los datos necesarios. Mientras se obtienen los datos, tal vez el componente pueda mostrar un indicador de carga.
Hay otra forma de utilizar lo que se conoce como route resolver
, que permite obtener datos antes de navegar a la nueva ruta.
Una API que está disponible para su uso es la API de Hacker News . Hacker News es un sitio web para compartir enlaces y debatir sobre ellos. La API se puede utilizar para recuperar las publicaciones más populares y mostrar información sobre publicaciones individuales.
En este tutorial, implementará un solucionador de ruta que obtiene datos de la API de Hacker News antes de navegar a una ruta que muestra los datos recopilados.
Prerrequisitos
Para completar este tutorial, necesitarás:
- Node.js instalado localmente, lo cual puedes hacer siguiendo Cómo instalar Node.js y crear un entorno de desarrollo local .
- Algunos conocimientos sobre la configuración de un proyecto Angular .
Este tutorial fue verificado con Node v15.3.0, npm
v6.14.9, @angular/core
v11.0.1, @angular/common
v11.0.1, @angular/router
v11.0.1 y rxjs
v6.6.0.
Paso 1: Configuración del proyecto
Para el propósito de este tutorial, construirás a partir de un proyecto Angular predeterminado generado con @angular/cli
.
- npx @angular/cli new angular-route-resolvers-example --style=css --routing --skip-tests
Esto configurará un nuevo proyecto Angular con estilos establecidos en “CSS” (a diferencia de “Sass”, Less” o “Stylus”), enrutamiento habilitado y omisión de pruebas.
Navegue hasta el directorio del proyecto recién creado:
- cd angular-route-resolvers-example
En este punto, tienes un nuevo proyecto Angular con @angular/router
.
Paso 2: creación de un solucionador
Comencemos por implementar un solucionador que devuelva una cadena después de un retraso de 2 segundos. Esta pequeña prueba de concepto puede ayudar a explorar los aspectos básicos de las rutas de cableado que se pueden aplicar a proyectos más grandes.
Primero, crea una clase separada para el solucionador en un archivo propio:
- ./node_modules/@angular/cli/bin/ng generate resolver news
Esto se utilizará @angular/cli
para generar un solucionador llamado news
:
src/app/noticias.resolver.ts
import { Injectable } from '@angular/core';import { Resolve } from '@angular/router';import { Observable, of } from 'rxjs';import { delay } from 'rxjs/operators';@Injectable({ providedIn: 'root'})export class NewsResolver implements ResolveObservablestring { resolve(): Observablestring { return of('Route!').pipe(delay(2000)); }}
Para implementar la interfaz del enrutador Angular, Resolve
es necesario que la clase tenga un resolve
método. Lo que se devuelva desde ese método serán los datos resueltos.
Este código devolverá un observable que envuelve una cadena después de un retraso de 2 segundos.
Paso 3: Configuración de rutas
Para poder experimentar dos rutas diferentes, necesitarás dos componentes nuevos. home
Esta será la página de inicio y top
contará con las publicaciones más importantes de la API de Hacker News.
Primero, use @angular/cli
para generar un home
componente:
- ./node_modules/@angular/cli/bin/ng generate component home
Luego, use @angular/cli
para generar un top
componente:
- ./node_modules/@angular/cli/bin/ng generate component top
Ahora puede configurar el módulo de enrutamiento para incluir el solucionador.
src/app/app-routing.module.ts
import { NgModule } from '@angular/core';import { Routes, RouterModule } from '@angular/router';import { NewsResolver } from './news.resolver';import { TopComponent } from './top/top.component';import { HomeComponent } from './home/home.component';const routes: Routes = [ { path: '', pathMatch: 'full', component: HomeComponent }, { path: 'top', component: TopComponent, resolve: { message: NewsResolver } }];@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule]})export class AppRoutingModule { }
Observe cómo se proporciona el solucionador como si fuera un servicio y luego se incluye el solucionador con la definición de ruta. Aquí, los datos resueltos estarán disponibles bajo la message
clave.
Paso 4: Acceso a los datos resueltos en el componente
En el componente, puede acceder a los datos resueltos utilizando la data
propiedad del objeto ActivatedRoute
de snapshot
:
src/app/top/top.component.ts
import { Component, OnInit } from '@angular/core';import { ActivatedRoute } from '@angular/router';@Component({ ... })export class TopComponent implements OnInit { data: any; constructor(private route: ActivatedRoute) {} ngOnInit(): void { this.data = this.route.snapshot.data; }}
Ahora, en el componente, puedes acceder al Route!
mensaje de la siguiente manera:
src/app/top/top.modulo.html
pThe message: {{ data.message }}/p
En este punto, puedes compilar tu aplicación:
- npm start
Y visitar localhost:4200/top
en un navegador web.
OutputThe message: Route!
Observarás al navegar hacia la top
ruta que ahora hay un retraso de 2 segundos porque los datos se resuelven primero.
Paso 5: Resolución de datos desde una API
Hagamos que las cosas sean más reales obteniendo datos de una API. Aquí crearás un servicio que obtenga datos de la API de Hacker News.
Necesitará HttpClient para solicitar el punto final.
Primero, agrega el HttpClientModule
a app.module.ts
:
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { HttpClientModule } from '@angular/common/http';import { AppRoutingModule } from './app-routing.module';import { AppComponent } from './app.component';@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent]})export class AppModule { }
Luego, crea un nuevo servicio:
- ./node_modules/@angular/cli/bin/ng generate service news
Esto se utilizará @angular/cli
para generar un servicio llamado news
:
src/app/noticias.servicio.ts
import { Injectable } from '@angular/core';import { HttpClient } from '@angular/common/http';@Injectable({ providedIn: 'root'})export class NewsService { constructor(private http: HttpClient) { } getTopPosts() { const endpoint = 'https://hacker-news.firebaseio.com/v0/topstories.json'; return this.http.get(endpoint); }}
Y ahora puedes reemplazar el código de cadena NewsResolver
con NewsService
:
src/app/noticias.resolver.ts
import { Injectable } from '@angular/core';import { Resolve } from '@angular/router';import { Observable } from 'rxjs';import { NewsService } from './news.service';export class NewsResolver implements Resolveany { constructor(private newsService: NewsService) {} resolve(): Observableany { return this.newsService.getTopPosts(); }}
En este punto, si miras la top
ruta en un navegador, se te presentará una lista de números que representan id
algunas de las publicaciones principales en Hacker News.
Paso 6: Acceso a los parámetros de ruta
Puede obtener acceso a los parámetros de ruta actuales en su resolver usando el ActivatedRouteSnapshot
objeto.
A continuación se muestra un ejemplo en el que utilizaría un resolver para obtener acceso al id
parámetro de la ruta actual.
Primero, use el @angular/cli
para generar un resolver llamado post
:
- ./node_modules/@angular/cli/bin/ng generate resolver news
Luego, modifíquelo post.resolver.ts
para utilizar ActivatedRouteSnapshot
:
fuente/aplicación/post.resolver.ts
import { Injectable } from '@angular/core';import { Resolve, ActivatedRouteSnapshot } from '@angular/router';import { Observable } from 'rxjs';import { NewsService } from './news.service';@Injectable({ providedIn: 'root'})export class PostResolver implements Resolveany { constructor(private newsService: NewsService) {} resolve(route: ActivatedRouteSnapshot): Observableany { return this.newsService.getPost(route.paramMap.get('id')); }}
A continuación, agregue un getPost
método a NewsService
:
src/app/noticias.servicio.ts
// ...export class NewsService { constructor(private http: HttpClient) { } // ... getPost(postId: string) { const endpoint = 'https://hacker-news.firebaseio.com/v0/item'; return this.http.get(`${endpoint}/${postId}.json`); }}
Y agregamos PostResolver
y la post/:id
ruta a app-routing.module.ts
:
src/app/app-routing.module.ts
// ...import { PostResolver } from './post.resolver';// ...const routes: Routes = [ // ... { path: 'post/:id', component: PostComponent, resolve: { newsData: PostResolver } }];// ...
A continuación, crea el nuevo PostComponent
:
- ./node_modules/@angular/cli/bin/ng generate component post
Luego, modifique post.component.ts
para utilizar datos de instantáneas:
src/app/post/post.component.ts
import { Component, OnInit } from '@angular/core';import { ActivatedRoute } from '@angular/router';@Component({ ... })export class PostComponent implements OnInit { data: any; constructor(private route: ActivatedRoute) { } ngOnInit(): void { this.data = this.route.snapshot.data; }}
Y modificar post.component.html
para mostrar el title
:
src/aplicación/publicación/publicación.componente.html
p{{ data.newsData.title }}/p
Ahora, si un usuario accede a , se resolverán http://localhost:4200/post/15392112
los datos del ID de la publicación .15392112
Paso 7: Manejo de errores
En caso de que se produzca un error al obtener los datos, puede detectarlo y solucionarlo en el solucionador utilizando el operador catch de RxJS . Por ejemplo, algo como esto:
src/app/noticias.resolver.ts
import { Injectable } from '@angular/core';import { Resolve } from '@angular/router';import { Observable, of } from 'rxjs';import { catchError } from 'rxjs/operators';import { NewsService } from './news.service';@Injectable()export class NewsResolver implements Resolveany { constructor(private newsService: NewsService) {} resolve(): Observableany { return this.newsService.getTopPosts().pipe(catchError(() = { return of('data not available at this time'); })); }}
O podría devolver un EMPTY
observable y devolver al usuario a la ruta raíz:
src/app/noticias.resolver.ts
import { Injectable } from '@angular/core';import { Router, Resolve } from '@angular/router';import { Observable, EMPTY } from 'rxjs';import { catchError } from 'rxjs/operators';import { NewsService } from './news.service';@Injectable()export class NewsResolver implements Resolveany { constructor(private router: Router, private newsService: NewsService) {} resolve(): Observableany { return this.newsService.getTopPosts().pipe(catchError(() = { this.router.navigate(['/']); return EMPTY; })); }}
Estos dos enfoques conducirán a una mejor experiencia de usuario si hay un error al recuperar datos de la API.
Conclusión
En este tutorial, implementó un solucionador de ruta que obtiene datos de la API de Hacker News antes de navegar a una ruta que muestra los datos recopilados. Esto se logró utilizando @angular/router
, @angular/common/http
y rxjs
.
Si desea obtener más información sobre Angular, consulte nuestra página de temas de Angular para ver ejercicios y proyectos de programación.
Deja una respuesta