クエリパラメータをうけとって初期データなどを取得してからレンダリングしたいみたいなパターンの時、もしくは初期データをあらかじめ用意しておきたい場合など
コンポーネントのonInit
に書いていくと複雑になればなるほどコードが膨れ上がっていってしまいます
さらに画面数が増えた場合などだいたいやってることは同じなのにonInit
に書いてあるみたいなことが増えてきます
処理を共通化、分離したいですよね
そこでresolverの出番です
resolverを使うことで初期データの読み込みをしてからコンポーネントの描画処理をしてくれます
https://angular.io/api/router/Resolveangular.io
サンプルコード(一部抜粋)
- app/services/campaign.service.ts
..... ..... @Injectable() export class CampaignService { constructor(private http: HttpClient) {} getCampaigns(accountId: number): Observable<any> { const requestUrl = `https://localhost/api/campaigns?account_id=${accountId}`; return this.http.get(requestUrl).pipe(catchError(this.handleError)); } }
親accountIDを受け取ってひもづくcampaign一覧を取得する処理
- app/resolvers/campaign.resolve.ts
..... ..... @Injectable() export class CampaignResolver implements Resolve<any> { constructor(private campaignService: campaignService) {} resolve(route: ActivatedRouteSnapshot) { const accountId = route.queryParams['account_id']; return accountId ? this.campaignService.getCampaigns(accountId) : []; } }
getのクエリパラメータを受け取ってcampaignService経由でリソースを取得
ここで返した値がコンポーネント側で使えるようになる
- campaign.routing.module.ts
import { RouterModule, Routes } from '@angular/router'; import { ModuleWithProviders } from '@angular/core'; import { CampaignResolver } from './resolvers'; import { CampaignComponent } from './campaign.component'; const campaignRoutes: Routes = [ { path: '', component: CampaignComponent, resolve: { campaigns: CampaignResolver } } ]; export const campaignRouting: ModuleWithProviders = RouterModule.forChild( campaignRoutes );
例だと一個だけですがresolverを複数定義することも可能です
- campaign.component.ts
..... ..... public campaigns: Campaign[]; constructor( private route: ActivatedRoute ){} ngOnInit() { this.route.data.subscribe(data => { this.campaigns = data['campaigns']; }); }
route.data
の中にresolverで解決したデータが入っているので初期化処理でsubscribeしてインスタンス変数に代入します
これでコンポーネント側のコードが少しすっきりしますね
同じような処理もresolverを使うことでまとめることができて便利です
サンプルだとそこまで変わらなそうですが条件分岐などが増えてくると結構効いてきます
また、httpClientでリソースをとってくる処理だけじゃなくクエリパラメータによって初期データが変わる動作などにも使えそうです