Angular Routerメモ
(Angular v.4.3.6を利用)
- 参考
- リンクを設定したい
- ts内で遷移の制御をしたい
- コンポーネント内でパラメータを取得したい
- 特定のRouteに紐付けないパラメータを利用したい
- 前回のURLを取得したい
- アプリ初期時に処理を追加したい
- Routerのナビゲーションイベントを確認したい
- コンポーネントの再利用について知りたい
- RouterとActivatedRouteについて知りたい
- その他
参考
リンクを設定したい
routerLink
を利用
通常
<a routerLink="/path">link</a> <!-- relative routerLink --> <a routerLink="./path">link</a>
パラメータがついたリンク
<!-- route param (/path/1) --> <a [routerLink]="['/path', 1 ]">link</a> <!-- matrix param (/path;matrixParam=value) --> <a [routerLink]="['/path', { matrixParam: 'value' } ]">link</a> <!-- query param (/path?page=1) --> <a [routerLink]="['/path']" [queryParams]="{ page: 1 }">link</a>
アンカー(#)がついたリンク
<!-- fragment (/path#anchor) --> <a [routerLink]="['/path']" fragment="anchor">link</a>
アクティブなリンクにクラスを設定したい
routerLinkActive
を利用
<a routerLink="/path" routerLinkActive="active">link</a> <a routerLink="/path" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">link</a> <a routerLink="/path" [routerLinkActive]="['active', 'border']">link</a>
ts内で遷移の制御をしたい
- コンポーネント、サービス内で制御したい時
Router#navigate
を利用
通常
this.router.navigate(['/path']); // relative link this.router.navigate(['path'], { relativeTo: this.route });
パラメータをつける
// route param (/path/1) this.router.navigate(['path', '1'], { relativeTo: this.route }); // matrix param (/path;matrixParam=value) this.router.navigate(['/path', { matrixParam: 'value' }]); // query param (/path?page=1) this.router.navigate(['/path'], { queryParams: { page: 1 } });
アンカー(#)をつける
// fragment (/path#anchor) this.router.navigate(['/path'], { fragment: 'anchor' });
クエリを保存して遷移したい
NavigationExtras#queryParamsHandling
を利用- https://angular.io/api/router/NavigationExtras#queryParamsHandling
preserve
,merge
が利用できる
- その他にも
NavigationExtras
を利用して、「ヒストリーにpushしない」「ヒストリーを置き換える」などの設定が可能
参考
コンポーネント内でパラメータを取得したい
Observableで取得
constructor(private route: ActivatedRoute) {} ngOnInit() { /** * Routeの設定が { path: 'view/:id' } * URLが /view/10;matrixParam=value?page=1 の場合 */ this.route.paramMap .subscribe((params: ParamMap) => { // params.keys.forEach(key => { const routeParam = params.get('id'); // -> 10 const matrixParam = params.get('matrixParam'); // -> value // }); }); this.route.queryParamMap .subscribe((params: ParamMap) => { const queryParam = this.route.snapshot.queryParamMap.get('page'); // -> 1 }); }
route.snapshot
から取得
constructor(private route: ActivatedRoute) {} // ... /** * Routeの設定が { path: 'view/:id' } * URLが /view/10;matrixParam=value?page=1 の場合 */ const routeParam = this.route.snapshot.paramMap.get('id'); // -> 10 const matrixParam = this.route.snapshot.paramMap.get('matrixParam'); // -> value const queryParam = this.route.snapshot.queryParamMap.get('page'); // -> 1
this.route.snapshot
はActivatedRouteSnapshot
- 初期データしか利用しない場合に利用
特定のRouteに紐付けないパラメータを利用したい
- クエリパラメータを利用
- https://angular.io/guide/router#query-parameters-and-fragments
In the route parameters example, you only dealt with parameters specific to the route, but what if you wanted optional parameters available to all routes? This is where query parameters come into play.
ルートパラメータの例では、ルートに固有のパラメータのみを扱いますが、オプションのパラメータをすべてのルートで使用できるようにしたい場合はどうなりますか?ここでクエリパラメータが有効になります。
- https://angular.io/guide/router#query-parameters-and-fragments
前回のURLを取得したい
アプリ初期時に処理を追加したい
- (Routerとは直接関係ないけど)
APP_INITIALIZER
を利用- 設定ファイルのロードや権限確認などに利用できそう
@NgModule({ providers: [ { provide: APP_INITIALIZER, useFactory: (sites:SitesService) => () => sites.load(), deps: [SitesService], multi: true, } ] }) export class AppModule { }
@Injectable() export class SitesService { constructor() { } load(): Promise<any> { return new Promise((resolve, reject) => { setTimeout(() => { // doing something // ... resolve(); }, 3000); }); } }
参考
- https://angular.io/api/core/APP_INITIALIZER
A function that will be executed when an application is initialized.
- What is best way to load json settings from the server? · Issue #9047 · angular/angular
- Hook into Angular Initialization Process – Hacker Noon
Routerのナビゲーションイベントを確認したい
Router.events
を利用- イベント一覧
constructor(private router: Router) { // 遷移開始時のイベントを確認 router.events.subscribe(event => { if (event instanceof NavigationStart) { console.log(event); // リダイレクトさせることも(一応)可能 // if (event.url !== '/view-a') { // router.navigate(['view-b']); // } } }); }
その他
- イベントのログをコンソールで確認(デバッグ用)
RouterModule.forRoot(appRoutes, { enableTracing: true })
コンポーネントの再利用について知りたい
routeConfig
が同じならコンポーネントは再利用される- パラメータが変わっても再描画はされない
// https://github.com/angular/angular/blob/54e02449549448ebab6f255f2da0b4396665c6f0/packages/router/src/route_reuse_strategy.ts#L66 shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { return future.routeConfig === curr.routeConfig; }
カスタマイズしたい
RouteReuseStrategy
を利用して挙動を変更できる
参考
- Force reload/refresh current route with RouteReuseStrategy · Issue #13831 · angular/angular
- Angular 2 Component Reuse Strategy – Julia Passynkova – Medium
RouterとActivatedRouteについて知りたい
- Angular Router: Understanding Router State – Angularを読むといいと思います
Any component instantiated by the router can inject its ActivatedRoute.
ActivatedRoute provides access to the url, params, data, queryParams, and fragment observables.
その他
複数のRouteを表示したい
<router-outlet></router-outlet> <!--popupという名前のoutletを設定 --> <router-outlet name="popup"></router-outlet> <!-- `path: 'compose'`に紐づけられているコンポーネントを表示 --> <a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
// `path: 'compose'`に紐づけられているコンポーネントを表示 this.router.navigate([{ outlets: { popup: 'compose' } }]); // null でクリアできる this.router.navigate([{ outlets: { popup: null }}]);
「遷移前に認証チェックをしたい」「遷移前に未保存のデータがあるか確認をしたい」など
CanActivate
,CanActivateChild
,CanDeactivate
を利用
遷移前にデータを読み込みたい
Resolve
を利用Observable
,Promise
(あるいは同期データ)を返すresolve
を定義する- https://angular.io/guide/router#fetch-data-before-navigating
- 読み込んだデータは
ActivatedRoute#data
やActivatedRoute#snapshot.data
から取得する- https://angular.io/api/router/ActivatedRoute#data
*(Routeで設定した
data
と同じように扱えるようになる)
- https://angular.io/api/router/ActivatedRoute#data
*(Routeで設定した
遅延読み込み
基本設定
- https://angular.io/guide/router#lazy-loading-route-configuration
loadChildren: 'app/admin/admin.module#AdminModule'
読み込み開始前にガードしたい
canLoad
を利用
プリロードさせたい
preloadingStrategy
を利用
RouterModule.forRoot( appRoutes, { // PreloadAllModules // https://angular.io/api/router/PreloadAllModules // guardされていないrouteが全てプリロードされる preloadingStrategy: PreloadAllModules } )
- PreloadingStrategyをカスタムすることも可能
@Injectable() export class CustomPreloadingStrategy implements PreloadingStrategy { preload(route: Route, load: () => Observable<any>): Observable<any> { // routeの設定情報に `data: { preload: true }` があればプリロードする if (route.data && route.data['preload']) { return load(); } else { return Observable.of(null); } } }