Angularのルーティングを0から学ぶ!パラメーター・ガード・階層構造など。

Angularのルーティングを0から学ぶ!パラメーター・ガード・階層構造など。

この記事では、 初心者から中級者向けにAngularのルーティングを説明する。

Angularでは、シングルページアプリケーションならではの細やかなページ設定を簡単に、直感的におこなうことができる。

ルーティングはアプリのセキュリティやユーザビリティに大きなインパクトを与える部分、しっかりと身に着けておきたい。

ルーティングとは?

まずはルーティングとは何かについて確認しておこう。

ウェブページのURLはホームアドレスとパスから構成される(呼び方にはバリエーションがある)。

今、あなたが読んでいるこのページを例にすると、

https://ugo.tokyo/angular-routing

ホームアドレスが「https://ugo.tokyo」で、「angular-routing」がパスに当たる。

これらの設定はWordpressというブログを管理するソフトウェアによって自動でおこなわれている。

Angularでは、こういったパスとコンポーネントの割り当てを自分でおこなうことができ、それらの振り分けの処理をルーティングと呼ぶ。

シングルページアプリケーションの定義
Angularはシングルページアプリケーション(以下、SPA)。「シングルページ」と聞くとパスのような概念が存在しないように感じるかもしれないが、そうでは無い。Angularは様々なコンポーネントを凝縮しひとつのファイル内に納めているが、その中にはパスを制御する仕組みがある。SPAは最初の読み込みに時間が掛かるが、ページ遷移が速いのが利点だ。なお、Angularではページの閲覧履歴も管理されている。

Angularのルーティングの仕組み

次にAngularのルーティングの仕組みを説明しよう。

Angularページはコンポーネントの組み合わせによって構成される。

ルーティングはそれぞれのパスにコンポーネントを割り当てることによっておこなう

例を挙げると

  • /login ⇒ LoginComponent
  • /dashboard ⇒ DashboardComponent

といった感じになる。

設定したパスとコンポーネントの割り当てはAngularのRouterModuleによって管理される

基本的なルーティング

では、より具体的なルーティングの設定方法を見ていこう。

router-outletを配置する

Angularでルーティングを使用するためには、まずはHTMLファイル上のルーティングを読み込む箇所にrouter-outletを配置する

<router-outlet></router-outlet>

ng newコマンドを使用して新しいプロジェクトを作成した場合は、app.module.html内にrouter-outletが配置されているのを確認できる。

Webアプリケーションの多くは画面上部や左側にメニューなどの操作をおこなうツールバーを備えている。アプリ内に常に表示しておきたいコンポーネントはルーターの外側に配置しておくようにしよう

以下の例では、黒枠で囲ったヘッダー・フッター部分は常に表示しておきたいのでルーターの外側に配置している。

routingファイルの設定

ルーティングの設定はapp.module.tsかapp-routing.module.tsファイルに記述する。

ngコマンドを使用して新しいプロジェクトを作成した場合はroutingファイルを作成するか否か尋ねられる。yesと答えた場合はapp-routing.module.tsが作成される。

以下の例はapp-routing.module.tsの記述例だ。

const routes: Routes = [
  { path: 'login', component: LoginComponent },
  { path: 'dashboard', component: DashboardComponent },
  { path: 'user-info', component: UserInfoComponent },
  { path: '**', component: LoginComponent }
];

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

routes変数にパスとコンポーネントの組み合わせを記述する。

Angularが更新されたら、ブラウザのURLにパスを入力して正しい画面が表示されるか確認しよう。

表示されない場合はapp.module.tsにRouterModuleがインポートされているか確認する。

なお、’**’は入力されたパスにマッチするパターンが無かった際に開くコンポーネントを指定できる。

‘**’を使用する際の注意
パスの照合はリストの上から順番におこなわれる。’**’を最初に記述するとそれ以下のパスはチェックされない。’**’は一番最後に記述するようにしよう。

パラメーターの受け渡し

次にルーティングを使用したパラメーターの受け渡し方法を説明する。

ルートパラメーター

Angularでは、ルーティングを使用してコンポーネントに値を引き渡す方法が複数ある。

最初に紹介する「ルートパラメーター」は渡したい値をURL内に記述する方法。

(例)https://sample.com/user-info/15

ここでは15が渡す値となる。

ルートパラメーターを使用する場合、routingファイルに以下のようにセミコロンと共にパラメーター名を記述する。

{ path: 'user-info/:userId', component: UserInfoComponent },

コンポーネントにて受け取った値を読み取る際は、以下のようにActivatedRouteからsubscribeする。

this.activatedRoute.params.subscribe(params => {
   console.log(params['userId']);
});

クエリパラメーター

URLにクエリパラメーターを付加することによって、パラメーターを引き渡すこともできる。

クエリパラメーターは以下のようにURLに?を付けてキーとバリューを指定する。

(例)http://localhost:4200/user-info?name=Yoshi&age=40

値を受け取る際はActivatedRouteのqueryParmsを使用する。

this._activatedRoute.queryParams.subscribe(params => {
  console.log(params['name']);
  console.log(params['age']);
});

クエリパラメーターを使用する場合はroutingファイルでの設定はそのままでいい。

データプロパティ

routingファイルに値を記述することによってパラメーターをダイレクトに渡すこともできる。

その際にはrouteオブジェクトにdataプロパティを付け足す。

  { path: 'user-info', 
    component: UserInfoComponent, 
    data: { type: 'normal' } 
  }

値を受け取る際は ActivatedRouteのdataを使用する。

this._activatedRoute.data.subscribe(datas => {
	console.log(datas['type']);
});

応用的なルーティング

次に応用的なルーティングの使い方をいくつか紹介しよう。

ガード機能

ガード機能はページの表示を許可するか否かを決定するための制御機能。

以下のようなケースで使用することができる。

  • ログインしたユーザのみページにアクセスできるように制御したい。
  • 会員のグレードごとに表示できるページを制限したい。
  • 有効なパラメーターとともに遷移をしてきた時のみページを表示したい。

また、ガード機能にまつわるプロパティにはおもに以下の3つがある。

  • canActivate – ルートへの遷移を許可するか決める。
  • canActivateChild – 子ルートへの遷移を許可するか決める。
  • canDeactivate – 現在のコンポーネントからの遷移を許可するかどうか決める。

ここでは、canActivateを例に実装例を見てみよう。

以下はGuardクラスの実装例でユーザがログインしているかどうかを基準にページへの遷移を許可するかどうかを決定している。

ログインしていなかった場合はログイン画面へと遷移するようになっている。

import {Injectable} from "@angular/core";
import {ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot} from "@angular/router";

@Injectable()
export class AuthenticationGuard implements CanActivate {

  constructor(private _authService: AuthenticationService,
              private _router: Router) {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if (!this._authService.isUserLoggedIn()) {
      this._router.navigate(['login']);
    }
    return true;
  }
}

routingファイルには以下のように記述する。

{ 
	path: 'dashboard', 
	component: DashboardComponent, 
	canActivate: [ AuthenticationGuard ] 
}

階層構造(入れ子構造・ネスト)

次に階層構造(入れ子構造・ネストとも呼ばれる)を持つroutingの例を紹介しよう。

以下の例では、URLのパスによってUserInfoComponentの中にAddressComponentもしくはContactComponentのいずれかを表示させている。

  {
    path: 'user-info', 
    component: UserInfoComponent, 
    children: [
      {
      path: 'address', component: AddressComponent
      },
      {
        path: 'contact', component: ContactComponent
      }
    ]
  }

それぞれを呼び出す際は”/user-info/address”、”/user-info/contact”といったパスを入力する。

この例ではUserInfoComponentの中にもrouter-outletを配置する必要がある。