Router と Component には何かしらの生成、消滅などイベントが発生したときに実行されるイベントトリガーのような機能があります。

  • Router Guards
  • Component Lifecycle Hook
  • Router Event

実際のアプリケーション開発ではよく使う(ページ遷移して良いのか良くないのかを判断するための処理を記載することは良くあります)ことがありますが、ここでは実験的にプログラムを記載してみます。

Router Guards

ルーティングには Routing Guards という機能があり、ページ遷移するときのイベント処理やセキュリティとして問題がある場合に遷移禁止等処理が行えるようになっています。具体的には5つの Guards があります。

Guards 内容
CanActivate ルートへのナビゲーション評価
CanActivateChild 小ルートへのナビゲーション評価
CanDeactivate 現在のルートからナビゲーションを評価
Resolve アクティブ化する前のプリフェッチ評価
CanLoad 非同期ルートの評価

について Guards を定義します。

$ ng g guard app
  create src/app/app.guard.spec.ts (340 bytes)
  create src/app/app.guard.ts (400 bytes)
$

生成されるファイル app.quard.ts

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AppGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}

HomeComponent に Routing Guards を定義

今回は処理をするというよりも、コンソールにログを出力することのみ記載しています。

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AppGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
      console.log('canActivate', 'next', next, 'state', state);
    return true;
  }
}

これを app-routing.module.ts に設定します。

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { HomeComponent } from './home/home.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

import { AppGuard } from './app.guard';

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full'},
  { path: 'home', component: HomeComponent, canActivate: [AppGuard] },
  { path: 'pages', loadChildren: './pages/pages.module#PagesModule', canActivate: [AppGuard] },
  { path: '**', component: PageNotFoundComponent, canActivate: [AppGuard] }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

次に app.module.ts にプロバイダ登録します。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule }   from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

import { AppGuard } from './app.guard';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    PageNotFoundComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule
  ],
  providers: [AppGuard],
  bootstrap: [AppComponent]
})
export class AppModule { }

さて、ブラウザを起動しコンソールを開いて下さい。メニューをクリックするとログが表示されます。この後は、もし戻りが false だったらといった具合に各自で評価してください。

Component Lifecycle Hooks

Component の Lifecycle Hooks については angular.io に詳しく書いています。実際にもう利用していて

ngOnInit() {
}

はそれにあたります。これ以外には

  • ngOnChanges
  • ngOnInit
  • ngDoCheck
  • ngAfterContentInit
  • ngAfterContentChacked
  • ngAfterViewInit
  • ngAfterViewChacked
  • ngOnDestroy

があります。 constructor も含め処理タイミングを確認すると良いでしょう。

注意事項として constructor に多くの処理を記述しないのがベターです。基本的に初期処理は ngOnInit に記載すべきです。

Router Event

Router の状態に応じてイベントが取れます

Router Event Description
NavigationStart ナビゲーションの開始時に実行されるイベント
RoutesRecognized ルータがURLを解析してルートが認識されたときに実行されるイベント
RouteConfigLoadStart ルータ遅延がルート設定をロードする前に実行されるイベント。
RouteConfigLoadEnd ルートが遅延ロードされた後に実行されるイベント
NavigationEnd ナビゲーションが正常に終了したときに実行されるイベント
NavigationCancel ナビゲーションがキャンセルされたときに実行されるイベント。これは、ナビゲーション中にルートガードがfalseを返すためです
NavigationError 予期しないエラーのためにナビゲーションが失敗したときに実行されるイベント

例えば app.component.ts で利用する場合には次のようにします。

import { Component } from '@angular/core';
import { Router, ActivatedRoute, NavigationStart } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  constructor(private router: Router) {
    this.router.events
      .filter(e => e instanceof NavigationStart)     
      .pairwise()
      .subscribe((e) => { console.log(e); }); 
   }
}

RxJS のオペレータを有効にするため filter, pairwise を追加します

import { Component } from '@angular/core';

import { Router, ActivatedRoute, NavigationStart } from '@angular/router';

import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/pairwise';

@Component({
  selector: 'ah-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.sass']
})
export class AppComponent {
  title = 'ah';
  constructor(private router: Router) {
    this.router.events
      .filter(e => e instanceof NavigationStart)     
      .pairwise()
      .subscribe((e) => { console.log(e); }); 
   }
}

results matching ""

    No results matching ""