فرید ذوالقدر
فرید ذوالقدر
خواندن ۵ دقیقه·۲ سال پیش

مفهوم Route Resolver در انگولار

در این مقاله سعی دارم درباره مفهومی به نام Route Resolver در انگولار برای شما صحبت کنم. امیدوارم تا انتهای این مقاله با من همراه باشید.

هنگامی که نیاز باشه داده ای از قبل از اینکه Route شما فعال بشه یا داده از Api گرفته بشه و آماده Navaigate شدن به صفحه مورد نظر بشین بهتر از مفهوم Route Resolver استفاده کنیم. در این آموزش، شما یک Route Resolver را پیاده سازی می کنید که قبل از رفتن به مسیری که داده های جمع آوری شده را نمایش می دهد. برای درک این موضوع با یه مثال کار خودمون شروع میکنیم:
در اول کار یه فایل به نام news.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 Resolve<Observable<string>> { resolve(): Observable<string> { return of('Route!').pipe(delay(2000)); } }

این کد یک قابل observable را که پس از 2 ثانیه تاخیر یک رشته را به عنوان خروجی بر می گرداند.

حالا توی قدم بعدی میریم AppModule خودمون یه تغییری میدیم:

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 { }

توجه کنید که چگونه Resolver درست مانند یک سرویس ارائه می شود و سپس شما آن را با تعریف مسیر اضافه می کنید.

حالا نوبت دسترسی به داده توی Component خودمون رسیده، در کامپوننت، می‌توانید با استفاده از ویژگی Data به Object snapshot ActivatedRoute به داده‌های اون دسترسی داشته باشید:

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; } }

در نهایت توی کد html خودمون می نویسیم :

<p>The message: {{ data.message }}</p>

اینم از خروجی ما :

The message: Route!

خب حالا از اینجا به بعد می خوایم یه سرویس راه بندازیم و از اینجا یه api صدا بزنیم و داده اون ببریم توی route resolver و از اونجا ببریم توی کامپوننت.

برای این کار میایم و ماژول HttpClientModule برای ارتباط با api توی app.module.ts اضافه می کنیم.

بعدش یه سرویس مثلا به نام news.service.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); } }

حالا لازم یه تغییر توی news.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 Resolve<any> { constructor(private newsService: NewsService) {} resolve(): Observable<any> { return this.newsService.getTopPosts(); } }

می توانید با استفاده از شی ActivatedRouteSnapshot به پارامترهای مسیر فعلی خود دسترسی پیدا کنید. در اینجا مثالی وجود دارد که در آن از یک Resolver برای دسترسی به پارامتر id مسیر فعلی استفاده می کنید.

ابتدا از @angular/cli برای ایجاد یک Resolver به نام پست استفاده کنید:

داخل فایل 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 Resolve<any> { constructor(private newsService: NewsService) {} resolve(route: ActivatedRouteSnapshot): Observable<any> { return this.newsService.getPost(route.paramMap.get('id')); } }

حالا لازم هستش متد getPost توی NewsService اضافه کنیم:

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`); } }

حالا باید بریم توی app.module.ts بخش routing عوض کنیم:

import { PostResolver } from './post.resolver'; // ... const routes: Routes = [ // ... { path: 'post/:id', component: PostComponent, resolve: { newsData: PostResolver } } ]; // ...

توی قدم بعدی برای دریافت و نمایش اطلاعات کامپوننت 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; } }

توی HTML همین کامپوننت هم میاریم:

<p>{{ data.newsData.title }}</p>

بعد از خروجی گرفتن و اجرای پروژه می بینیم که این پروژه مقدار نهایی ما نشون میده.

اما در گام آخر در نظر دارم نمایش خطای این مورد هم راه اندازی کنم.

برای این کار یه بار دیگه news.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 Resolve<any> { constructor(private newsService: NewsService) {} resolve(): Observable<any> { return this.newsService.getTopPosts().pipe(catchError(() => { return of('data not available at this time'); })); }
}

و یا به این صورت بنویسم فایل news.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 Resolve<any> { constructor(private router: Router, private newsService: NewsService) {} resolve(): Observable<any> { return this.newsService.getTopPosts().pipe(catchError(() => { this.router.navigate(['/']); return EMPTY; })); } }

ممنون از توجه خوبتون امیدوارم این مقاله براتون مفید باشه.

:))

angular
شاید از این پست‌ها خوشتان بیاید