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 ngOnInitel 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, npmv6.14.9, @angular/corev11.0.1, @angular/commonv11.0.1, @angular/routerv11.0.1 y rxjsv6.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/clipara 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, Resolvees necesario que la clase tenga un resolvemé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. homeEsta será la página de inicio y topcontará con las publicaciones más importantes de la API de Hacker News.
Primero, use @angular/clipara generar un homecomponente:
- ./node_modules/@angular/cli/bin/ng generate component home
Luego, use @angular/clipara generar un topcomponente:
- ./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 messageclave.
Paso 4: Acceso a los datos resueltos en el componente
En el componente, puede acceder a los datos resueltos utilizando la datapropiedad del objeto ActivatedRoutede 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/topen un navegador web.
OutputThe message: Route!
Observarás al navegar hacia la topruta 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 HttpClientModulea 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/clipara 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 NewsResolvercon 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 topruta en un navegador, se te presentará una lista de números que representan idalgunas 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 ActivatedRouteSnapshotobjeto.
A continuación se muestra un ejemplo en el que utilizaría un resolver para obtener acceso al idparámetro de la ruta actual.
Primero, use el @angular/clipara generar un resolver llamado post:
- ./node_modules/@angular/cli/bin/ng generate resolver news
Luego, modifíquelo post.resolver.tspara 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 getPostmé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 PostResolvery la post/:idruta 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.tspara 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.htmlpara 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/15392112los 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 EMPTYobservable 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/httpy 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