Angularでルーティング機能を実装するには? - RouterModule:Angular TIPS
RouterModuleを使用して、Angularアプリにルーティング機能を実装し、ページ内に表示する内容を動的に切り替える方法を説明。
【対応バージョン】
Angular 5以降。v5時点で執筆し、v6で動作を確認しました。
ルーティングとは、「リクエストされたURLに応じて、処理の受け渡し先(コンポーネント)を決定すること」、または、その仕組みのことを言います。ルーティングは、1つのページの中で表示すべきコンテンツだけを動的に切り替えていくアプリ――いわゆるSPA(Single Page Application)の開発には欠かせない仕組みです。
Angularでも標準的に、RouterModuleモジュールというルーティングの仕組み(=ルーター)を備えています。本稿では、まず、このRouterModuleモジュールを利用したルーティングの基本的な用法について解説します。
本稿で作成するのは、以下の図のような例です。リンクリストをクリックすることで、メイン領域(ページ下部)に対応するコンテンツを表示します。
ルーティングでは、関係するファイルも増えてきますので、本稿で利用するファイル一式をまとめておきます。
| ファイル | 概要 | 
|---|---|
| index.html | メインページ | 
| app.module.ts | メインモジュール | 
| app.routing.ts | ルーティングの設定 | 
| app.component.xxxx | ルートコンポーネント | 
| home.component.xxxx/ contents.component.xxxx/ error.component.xxxx  | 
ルーティング経由で呼び出されるコンポーネント | 
| 本稿のサンプルを構成するファイル | |
では、個々のファイルについて見ていきます。
基底パスの設定
まずは、メインページ(index.htmlファイル)からです。ルーターが基点とするパスを<base>要素で宣言しておきます。Angular CLIを利用している場合には、最初からindex.htmlファイルに含まれています。
<base href="/">
ルーティングの定義
ルーティングを利用するには、まず、RouterModuleモジュールに対してルーティング定義(ルート)を準備しなければなりません。ルートとは、大ざっぱに言ってしまうならば、URLパターンとコンポーネントの組み合わせです。ルーティングでは、「リクエストされたURLに応じて、処理の受け渡し先(コンポーネント)を決定する」のでした。
例えば本稿では、以下のようなルートが定義されているものとします。
| リクエストURL | コンポーネント | 
|---|---|
| / | HomeComponent | 
| /contents | ContentsComponent | 
| それ以外 | ErrorComponent | 
| 本稿で定義するルーティング定義 | |
具体的なコードは、以下の通りです。
import { ModuleWithProviders }   from '@angular/core';
import { Routes, RouterModule }   from '@angular/router';
import { HomeComponent }  from './home.component';
import { ContentsComponent } from "./contents.component";
import { ErrorComponent } from './error.component';
// [1]ルートを定義
const myRoutes = [
  { path: 'contents', component: ContentsComponent },
  { path: '', component: HomeComponent },
  { path: '**', component: ErrorComponent }
];
// [2]ルーティング情報付きのRouterModuleモジュールを生成
export const MY_ROUTES: ModuleWithProviders = RouterModule.forRoot(myRoutes);
ルートは、以下のようなプロパティを持つオブジェクトとして表せます([1])。さまざまなプロパティが用意されていますが、まずは、パス(path)とコンポーネント(component)を最低限の構成と理解しておけばよいでしょう。その他のプロパティについては、後日別稿で解説の予定です。
| プロパティ | 概要 | 
|---|---|
| path | リクエストパス | 
| component | ルーティング先で利用するコンポーネント | 
| children | 子ルート情報 | 
| outlet | コンポーネントの表示先 | 
| redirectTo | リダイレクト先 | 
| data | コンポーネントに引き渡すデータ | 
| pathMatch | パス(path)の比較オプション | 
| canXxxxx | ガード機能(遷移の可否を判定するための仕組み) | 
| ルートで利用できるプロパティ | |
pathプロパティの「**」は、任意のパスを表します。ルート群の末尾に「**」ルートを用意しておくことで、そこまでのルートにマッチしなかったリクエストを最終的に補足し、処理できます。
後は、これら用意したルート群を、RouterModule.forRootメソッドに引き渡し、ルーティング情報付きのRouterModuleモジュールを生成します([2])。
メインモジュールへの登録
作成したルーティング情報(RouterModuleモジュール)は、メインモジュールに登録することで有効になります。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { MY_ROUTES }   from './app.routing';
import { AppComponent } from './app.component';
import { HomeComponent }  from './home.component';
import { ContentsComponent }  from './contents.component';
import { ErrorComponent } from './error.component';
@NgModule({
  // [2]各コンポーネントを登録
  declarations: [ AppComponent, HomeComponent,
    ContentsComponent, ErrorComponent ],
  // [1]RouterModuleモジュールをインポート
  imports: [ BrowserModule, MY_ROUTES ],
  providers: [],
  bootstrap: [ AppComponent ]
})
export class AppModule { }
APP_ROUTES(RouterModuleモジュール)は、他のモジュールと同じく、@NgModuleモジュールのimportsパラメーターでインポートできます([1])。また、ルーティングで利用するコンポーネントは、declarationsパラメーターで登録しておきます([2])。
メインコンポーネントの準備
個々のコンポーネントを呼び出すためのリンクと、その表示領域は、メインコンポーネントで用意しておきます。
import { Component } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
}
<ul>
  <!--[1]ルーター経由でページを遷移-->
  <li><a routerLink="/" routerLinkActive="current"
    [routerLinkActiveOptions]="{ exact: true }">
    ホーム</a></li>
  <li><a routerLink="/contents" routerLinkActive="current">
    記事を読む</a></li>
  <li><a routerLink="/dummy" routerLinkActive="current">
    不正なページを表示</a></li>
</ul>
<hr />
  <!--[2]コンテンツの埋め込み先-->
<router-outlet></router-outlet>
.current { background-color:yellow; }
ルーター経由でページを遷移する場合には、(標準的なhref属性ではなく)routerLinkディレクティブを使います([1])。
roureLinkActiveディレクティブは、リンク先が現在のパスと一致する場合に適用すべきスタイルクラス(ここではcurrent)を表します。スタイルそのものはstyleUrls(またはstyles)パラメーターで用意しておきます。
routerLinkActiveOptionsはroureLinkActiveディレクティブの属性で、スタイルを適用する際のオプションを表します。ここでは、exactオプションをtrueとすることで、パス文字列(ここでは「/」のみ)が完全に一致した場合にだけスタイルを適用するようにしています。exactオプションを指定しなかった場合、例えば「/hoge」「/foo」などの先頭だけが一致するパスにもスタイルが適用されてしまうので注意です。
後は、<router-outlet>要素(コンポーネント)で、コンテンツの埋め込み先を確保しておきます([2])。これでルーティングによって選択されたコンポーネントでの処理結果は、<router-outlet>要素の配下に反映されるようになります。
ルーター対応のコンポーネント
後は、個々のコンポーネントを用意するだけです。いずれもこれまでのTIPSで触れてきた以上の内容はありませんので、HomeComponentコンポーネントについてのみ掲載しておきます。完全なコードはダウンロードサンプルから確認してください。
import { Component } from '@angular/core';
@Component({
  templateUrl: './home.component.html',
})
export class HomeComponent { }
<div class="component">
  <h1>ホーム</h1>
  <p>Angular TIPSのページへようこそ</p>
  <img src="https://re.buildinsider.net/web/angulartips/index/icon.s.png"
    alt="Angular Tipsロゴ" />
</div>
以上を理解できたら、サンプルにアクセスしてみましょう。本稿冒頭の図のように、ページを遷移できれば、ルーティング機能は正しく動作しています。
Copyright© Digital Advantage Corp. All Rights Reserved.

