27 November 2021

Cách sử dụng trình Resolve với Angular Router

 


Giới thiệu

Một cách để xử lý việc truy xuất và hiển thị dữ liệu từ API là định tuyến người dùng đến một thành phần, sau đó trong ngOnInithook của thành phần đó gọi một phương thức trong một dịch vụ để lấy dữ liệu cần thiết. Trong khi lấy dữ liệu, có lẽ thành phần có thể hiển thị chỉ báo tải.

Có một cách khác để sử dụng cái được gọi là a route resolver, cho phép bạn lấy dữ liệu trước khi điều hướng đến tuyến đường mới.

Một API có sẵn để sử dụng là Hacker News API . Hacker News là một trang web để chia sẻ các liên kết và thảo luận về chúng. API có thể được sử dụng để truy xuất các bài đăng phổ biến nhất và hiển thị thông tin về các bài đăng riêng lẻ.

Trong hướng dẫn này, bạn sẽ triển khai một trình giải quyết tuyến đường lấy dữ liệu từ Hacker News API trước khi điều hướng đến một tuyến đường hiển thị dữ liệu đã thu thập.

Điều kiện tiên quyết

Để hoàn thành hướng dẫn này, bạn sẽ cần:

Hướng dẫn này đã được xác minh với Node v15.3.0, npmv6.14.9, @angular/corev11.0.1, @angular/commonv11.0.1, @angular/routerv11.0.1 và rxjsv6.6.0.

Bước 1 - Thiết lập dự án

Với mục đích của hướng dẫn này, bạn sẽ xây dựng từ một dự án Angular mặc định được tạo bằng @angular/cli.

  • npx @angular/cli new angular-route-resolvers-example --style=css --routing --skip-tests
 

Điều này sẽ định cấu hình một dự án Angular mới với các kiểu được đặt thành “CSS” (trái ngược với “Sass”, Less ”hoặc“ Stylus ”), bật định tuyến và bỏ qua các bài kiểm tra.

Điều hướng đến thư mục dự án mới được tạo:

  • cd angular-route-resolvers-example
 

Tại thời điểm này, bạn có một dự án Angular mới với @angular/router.

Bước 2 - Xây dựng trình phân giải

Hãy bắt đầu bằng cách triển khai trình phân giải trả về một chuỗi sau độ trễ 2 giây. Bằng chứng khái niệm nhỏ này có thể giúp khám phá các nguyên tắc cơ bản của các tuyến dây dẫn có thể được áp dụng cho các dự án lớn hơn.

Đầu tiên, hãy tạo một lớp riêng cho trình phân giải trong một tệp của chính nó:

  • ./node_modules/@angular/cli/bin/ng generate resolver news
 

Điều này sẽ sử dụng @angular/cliđể tạo một trình phân giải có tên news:

src / app / 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));
  }
}
 

Việc triển khai Resolvegiao diện của bộ định tuyến Angular yêu cầu lớp phải có một resolvephương thức. Bất cứ thứ gì được trả về từ phương thức đó sẽ là dữ liệu đã được giải quyết.

Mã này sẽ trả về một mã có thể quan sát được bao bọc một chuỗi sau thời gian trễ 2 giây.

Bước 3 - Định cấu hình các tuyến đường

Để trải nghiệm hai tuyến đường khác nhau, bạn sẽ cần hai thành phần mới. homesẽ là trang đích. Và topsẽ giới thiệu các bài đăng hàng đầu từ Hacker News API.

Đầu tiên, sử dụng @angular/cliđể tạo một homethành phần:

  • ./node_modules/@angular/cli/bin/ng generate component home
 

Sau đó, sử dụng @angular/cliđể tạo một topthành phần:

  • ./node_modules/@angular/cli/bin/ng generate component top
 

Bây giờ bạn có thể thiết lập mô-đun định tuyến để bao gồm trình phân giải.

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

Lưu ý cách trình phân giải được cung cấp giống như một dịch vụ và sau đó bạn bao gồm trình phân giải với định nghĩa tuyến đường. Tại đây, dữ liệu đã phân giải sẽ có sẵn dưới messagekhóa.

Bước 4 - Truy cập dữ liệu đã giải quyết trong thành phần

Trong thành phần, bạn có thể truy cập dữ liệu được giải quyết bằng cách sử dụng datatài sản của ActivatedRoute's snapshotđối tượng:

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

Bây giờ, trong thành phần, bạn có thể truy cập Route!thông báo như sau:

src / app / top / top.module.html
<p>The message: {{ data.message }}</p>
 

Tại thời điểm này, bạn có thể biên dịch ứng dụng của mình:

  • npm start
 

Và truy cập localhost:4200/toptrong trình duyệt web.

Output
The message: Route!

Bạn sẽ quan sát thấy khi điều hướng đến toptuyến đường hiện có độ trễ 2 giây vì dữ liệu được giải quyết trước.

Bước 5 - Giải quyết dữ liệu từ API

Hãy làm cho mọi thứ trở nên giống thực hơn bằng cách thực sự lấy một số dữ liệu từ một API. Tại đây, bạn sẽ tạo một dịch vụ lấy dữ liệu từ Hacker News API.

Bạn sẽ cần HttpClient để yêu cầu điểm cuối.

Đầu tiên, hãy thêm HttpClientModulevào 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 { }
 

Sau đó, tạo một dịch vụ mới:

  • ./node_modules/@angular/cli/bin/ng generate service news
 

Điều này sẽ sử dụng @angular/cliđể tạo một dịch vụ có tên news:

src / app / 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);
  }
}
 

Và bây giờ bạn có thể thay thế mã chuỗi NewsResolverbằng NewsService:

src / app / 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();
  }
}
 

Tại thời điểm này, nếu bạn nhìn vào toplộ trình trong trình duyệt, bạn sẽ thấy một danh sách các con số đại diện cho idcác bài đăng hàng đầu trên Hacker News.

Bước 6 - Truy cập các thông số tuyến đường

Bạn có thể có quyền truy cập vào các tham số tuyến đường hiện tại trong trình phân giải của mình bằng cách sử dụng ActivatedRouteSnapshotđối tượng.

Đây là một ví dụ trong đó bạn sẽ sử dụng một trình phân giải để có quyền truy cập vào thông idsố của tuyến đường hiện tại.

Đầu tiên, sử dụng @angular/cliđể tạo một trình phân giải có tên post:

  • ./node_modules/@angular/cli/bin/ng generate resolver news
 

Sau đó, sửa đổi post.resolver.tsđể sử dụng ActivatedRouteSnapshot:

src / app / 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'));
  }
}
 

Tiếp theo, thêm một getPostphương thức vào NewsService:

src / app / news.service.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`);
  }
}
 

Và thêm PostResolvervà post/:idtuyến đường đến 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 }
  }
];

// ...
 

Tiếp theo, tạo mới PostComponent:

  • ./node_modules/@angular/cli/bin/ng generate component post
 

Sau đó, sửa đổi post.component.tsđể sử dụng dữ liệu ảnh chụp nhanh:

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

Và sửa đổi post.component.htmlđể hiển thị title:

src / app / post / post.component.html
<p>{{ data.newsData.title }}</p>
 

Bây giờ nếu người dùng truy cập http://localhost:4200/post/15392112, dữ liệu cho id bài đăng 15392112sẽ được giải quyết.

Bước 7 - Xử lý lỗi

Trong trường hợp có lỗi khi tìm nạp dữ liệu, bạn có thể bắt và xử lý lỗi trong trình phân giải bằng cách sử dụng toán tử bắt của RxJS . Ví dụ như thế này:

src / app / 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');
    }));
  }
}
 

Hoặc bạn có thể trả về một EMPTYtệp có thể quan sát được và đưa người dùng trở lại đường dẫn gốc:

src / app / 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;
    }));
  }
}
 

Hai cách tiếp cận này sẽ dẫn đến trải nghiệm người dùng tốt hơn nếu có lỗi khi truy xuất dữ liệu từ API.

Phần kết luận

Trong hướng dẫn này, bạn đã triển khai một trình giải quyết tuyến đường lấy dữ liệu từ Hacker News API trước khi điều hướng đến một tuyến đường hiển thị dữ liệu đã thu thập. Điều này đạt được bằng cách sử dụng @angular/router@angular/common/httpvà rxjs.

0 nhận xét:

Post a Comment

 

BACK TO TOP

Xuống cuối trang