Как использовать преобразователи маршрутов с Angular Router
Введение
Один из способов обработки получения и отображения данных из API — направить пользователя к компоненту, а затем в хуке ngOnInit
этого компонента вызвать метод службы для получения необходимых данных. При получении данных, возможно, компонент может показывать индикатор загрузки.
Существует еще один способ использования так называемого преобразователя маршрутов
, который позволяет получить данные перед переходом к новому маршруту.
Одним из доступных для использования API является Hacker News API. Hacker News — это сайт для обмена ссылками и их обсуждения. API можно использовать для получения наиболее популярных сообщений и отображения информации об отдельных сообщениях.
В этом руководстве вы реализуете преобразователь маршрутов, который получает данные из Hacker News API перед переходом к маршруту, отображающему собранные данные.
Предпосылки
Для выполнения этого урока вам понадобятся:
- Node.js установлен локально, что можно сделать, следуя инструкциям по установке Node.js и созданию локальной среды разработки.
- Некоторое знакомство с настройкой проекта Angular.
Это руководство было проверено с помощью Node v15.3.0, npm
v6.14.9, @angular/core
v11.0.1, @angular/common
v11. 0.1, @angular/router
версии 11.0.1 и rxjs
версии 6.6.0.
Шаг 1 — Настройка проекта
Для целей этого руководства вы создадите проект Angular по умолчанию, сгенерированный с помощью @angular/cli
.
- npx @angular/cli new angular-route-resolvers-example --style=css --routing --skip-tests
Это настроит новый проект Angular со стилями, установленными на «CSS» (в отличие от «Sass», «Less» или «Stylus»), с включенной маршрутизацией и пропуском тестов.
Перейдите в только что созданный каталог проекта:
- cd angular-route-resolvers-example
На данный момент у вас есть новый проект Angular с @angular/router
.
Шаг 2 — Создание резольвера
Начнем с реализации резолвера, который возвращает строку после задержки в 2 секунды. Это небольшое доказательство концепции может помочь в изучении основ маршрутов проводки, которые можно применять в более крупных проектах.
Во-первых, создайте отдельный класс для распознавателя в собственном файле:
- ./node_modules/@angular/cli/bin/ng generate resolver news
Это будет использовать @angular/cli
для создания преобразователя с именем news
:
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));
}
}
Для реализации интерфейса Resolve
маршрутизатора Angular требуется, чтобы класс имел метод resolve
. Все, что возвращается из этого метода, будет разрешенными данными.
Этот код вернет наблюдаемую, которая переносит строку после задержки в 2 секунды.
Шаг 3 — Настройка маршрутов
Чтобы испытать два разных маршрута, вам понадобятся два новых компонента. home
будет целевой страницей. А в top
будут представлены самые популярные сообщения из Hacker News API.
Сначала используйте @angular/cli
для создания компонента home
:
- ./node_modules/@angular/cli/bin/ng generate component home
Затем используйте @angular/cli
для создания компонента top
:
- ./node_modules/@angular/cli/bin/ng generate component top
Теперь вы можете настроить модуль маршрутизации для включения резолвера.
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 { }
Обратите внимание, что преобразователь предоставляется точно так же, как служба, а затем вы включаете преобразователь в определение маршрута. Здесь разрешенные данные будут доступны по клавише message
.
Шаг 4 — Доступ к разрешенным данным в компоненте
В компоненте вы можете получить доступ к разрешенным данным, используя свойство data
объекта ActivatedRoute
snapshot
:
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;
}
}
Теперь в компоненте вы можете получить доступ к сообщению Route!
следующим образом:
<p>The message: {{ data.message }}</p>
На этом этапе вы можете скомпилировать ваше приложение:
- npm start
И посетите localhost:4200/top
в веб-браузере.
OutputThe message: Route!
При переходе к маршруту top
вы заметите, что теперь есть 2-секундная задержка, потому что данные обрабатываются первыми.
Шаг 5 — Разрешение данных из API
Давайте сделаем вещи более реальными, фактически получив некоторые данные из API. Здесь вы создадите службу, которая получает данные из Hacker News API.
Вам понадобится HttpClient для запроса конечной точки.
Сначала добавьте HttpClientModule
в 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 { }
Затем создайте новую службу:
- ./node_modules/@angular/cli/bin/ng generate service news
Это будет использовать @angular/cli
для создания службы с именем news
:
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);
}
}
И теперь вы можете заменить строковый код в NewsResolver
на NewsService
:
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();
}
}
На этом этапе, если вы посмотрите на маршрут top
в браузере, вам будет представлен список чисел, представляющих id
самых популярных сообщений в Hacker News.
Шаг 6 — Доступ к параметрам маршрута
Вы можете получить доступ к текущим параметрам маршрута в вашем преобразователе с помощью объекта ActivatedRouteSnapshot
.
Вот пример, где вы могли бы использовать преобразователь, чтобы получить доступ к параметру id
текущего маршрута.
Сначала используйте @angular/cli
для создания преобразователя с именем post
:
- ./node_modules/@angular/cli/bin/ng generate resolver news
Затем измените post.resolver.ts
, чтобы использовать ActivatedRouteSnapshot
:
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`);
}
}
И добавьте PostResolver
и маршрут post/:id
в app-routing.module.ts
:
// ...
import { PostResolver } from './post.resolver';
// ...
const routes: Routes = [
// ...
{
path: 'post/:id',
component: PostComponent,
resolve: { newsData: PostResolver }
}
];
// ...
Затем создайте новый PostComponent
:
- ./node_modules/@angular/cli/bin/ng generate component 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;
}
}
И измените post.component.html
, чтобы отобразить title
:
<p>{{ data.newsData.title }}</p>
Теперь, если пользователь переходит на http://localhost:4200/post/15392112
, данные для идентификатора сообщения 15392112
будут разрешены.
Шаг 7 — Обработка ошибок
В случае возникновения ошибки при извлечении данных вы можете отловить и устранить ошибку в распознавателе с помощью оператора catch RxJS. Что-то вроде этого, например:
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');
}));
}
}
Или вы можете вернуть наблюдаемый объект EMPTY
и вернуть пользователя к корневому пути:
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;
}));
}
}
Эти два подхода улучшат взаимодействие с пользователем в случае возникновения ошибки при получении данных из API.
Заключение
В этом руководстве вы реализовали преобразователь маршрутов, который получает данные из Hacker News API перед переходом к маршруту, отображающему собранные данные. Это было достигнуто за счет использования @angular/router
, @angular/common/http
и rxjs
.
Если вы хотите узнать больше об Angular, ознакомьтесь с нашей темой по Angular, где вы найдете упражнения и проекты по программированию.