サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

Angular 5入門 06: ルーティングで画面を切り替える


Angular 5入門 05: データをサービスにより提供する」は、データの取得や提供などの管理を、サービスのモジュールに分けました。本稿では、ルーティングの機能によって画面を切り替えます。ページのコンポーネントを差し替えるだけでなく、URLも改めることでページの遷移を示すのです。

Angular Version 6については「Angular 6入門 06: ルーティングで画面を切り替える」をお読みください

01 ルーティングのモジュールをつくる

ルーティングのモジュールをAngular CLIでつくります。コマンドラインツールでアプリケーションのディレクトリ(angular-tour-of-heroines)に移り、つぎのようにng generate moduleコマンドを打ち込んでください。ルーティングのモジュール(app-routing.module)がつくられ、以下のようなひな形のクラス(AppRoutingModule)が定められます。

ngコマンド

ng generate module app-routing --flat --module=app

src/app/app-routing.module.ts

import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
@NgModule({
	imports: [
		CommonModule
	],
	declarations: []
})
export class AppRoutingModule {}

ルーティングのモジュール(app-routing.module)のTypeScriptコードは、つぎのように書き替えましょう。ルーティングのライブラリ(app-routing.module)からRouterModuleクラスとRoutes型(type alias)をimportします。そのうえで、クラスはデコレータ関数NgModule()の引数オブジェクトに、exportsプロパティの配列要素として加えてください。プロパティimportsdeclarationsは除きます。

src/app/app-routing.module.ts

import {NgModule} from '@angular/core';
// import {CommonModule} from '@angular/common';
import {RouterModule, Routes} from '@angular/router';
@NgModule({
	/*
	imports: [
		CommonModule
	],
	declarations: []
	*/
	exports: [RouterModule]
})
export class AppRoutingModule {}

Routes型の定数(routes)に、以下のようにパス('heroines')とコンポーネント(HeroinesComponent)が定められたオブジェクトを配列要素として加えます。そのため、コンポーネントのクラス(HeroinesComponent)は、importしておかなければなりません。RoutesオブジェクトのプロパティpathはURLのパスに加える文字列で、componentはそのパスに遷移するときつくられるコンポーネントです。RouterModule.forRoot()メソッドは、引数のRoutesオブジェクトにもとづいてルーターを初期化します。そして、戻り値のモジュールを、デコレータ関数NgModule()に渡すオブジェクトのimportsプロパティに配列要素として加えることで、ルーティングのためのサービスやディレクティブが使えるようになるのです(「URLとリンクでコンポーネント表示を切り替える「Angular 2」のルーター」参照)。

src/app/app-routing.module.ts

import {HeroinesComponent} from './heroines/heroines.component';
const routes: Routes = [
	{path: 'heroines', component: HeroinesComponent}
];
@NgModule({
	imports: [RouterModule.forRoot(routes)],

})
export class AppRoutingModule {}

02 コンポーネントにルーティングの要素を加える

親コンポーネント(app.component)のテンプレートは、つぎのように要素を子コンポーネントの(app-heroines)からrouter-outlet(RouterOutlet)ディレクティブに差し替えます。router-outletはルーティングが遷移した表示に切り替えるディレクティブです。このディレクティブの要素には、はじめは何も表示されません(図001)。

src/app/app.component.html

<h1>{{title}}</h1>
<!--<app-heroines></app-heroines>-->
<router-outlet></router-outlet>
<app-messages></app-messages>

図001■router-outletの要素にははじめ何も表示されない

図001

ここで、ブラウザのルートURLに、つぎのように前述pathプロパティに与えたパスを加えます。すると、ルーテイングによりrouter-outletディレクティブの要素には、コンポーネントが差し込まれます(図002)。

http://localhost:4200/heroines

図002■ページにコンポーネントが差し込まれて表示される

図002

なお、router-outletは、RouterModuleクラスから提供されるディレクティブです。このクラスはルーテイングのモジュール(app-routing.module)がNgModule()デコレータ関数に渡したオブジェクトのexportsプロパティに配列要素として加え、そのクラス(AppRoutingModule)をアプリケーションモジュール(app.module)のimportsプロパティが配列に納めました。こうして、アプリケーションのコンポーネントがrouter-outletディレクティブを使えるようになったのです。

src/app/app-routing.module.ts

@NgModule({

	exports: [RouterModule]
})
export class AppRoutingModule {}

src/app/app.module.ts

@NgModule({

	imports: [

		AppRoutingModule
	],

})
export class AppModule {}

03 ルーテイングのリンクを加える

ページのリンクからルーティングできるようにしましょう。親コンポーネント(app.component)のテンプレートに、つぎのように<nav>要素の中に<a>要素でリンクを加えます。属性にrouterLink(RouterLink)ディレクティブで与えるのが遷移先のパス("/heroines")です。このディレクティブもRouterModuleクラスから提供されます。

src/app/app.component.html

<h1>{{title}}</h1>
<nav>
	<a routerLink="/heroines">ヒロインたち</a>
</nav>

これで、はじめのページにリンクが加わり、クリックするとリスト表示のコンポーネントが差し込まれます。ブラウザのURLのパスも、ルートから書き替わるはずです。以下のコード001のCSSをコンポーネント(app.component)に定めれば、スタイルが整います(図001)。

図003■リンクをクリックするとリストが表示される

図003

コード001■親コンポーネントのCSSの定め

src/app/app.component.css

h1 {
	font-size: 1.2em;
	color: #999;
	margin-bottom: 0;
}
h2 {
	font-size: 2em;
	margin-top: 0;
	padding-top: 0;
}
nav a {
	padding: 5px 10px;
	text-decoration: none;
	margin-top: 10px;
	display: inline-block;
	background-color: #eee;
	border-radius: 4px;
}
nav a:visited, a:link {
	color: #607D8B;
}
nav a:hover {
	color: #039be5;
	background-color: #CFD8DC;
}
nav a.active {
	color: #039be5;
}

04 ダッシュボードのコンポーネントを加える

新たにダッシュボードのコンポーネントをつくって、ナビゲーションのリンクに加えましょう。つぎのように、ng generate componentコマンドでコンポーネント(dashboard.component)を生成します。

ngコマンド

ng generate component dashboard

コンポーネント(dashboard.component)のTypeScriptコードには、つぎのように書き加えてください。クラス(DashboardComponent)の組み立ては、リスト表示のコンポーネントとよく似ています(「Angular 5入門 05」コード002「サービスとリスト表示コンポーネントのTypeScriptコード」参照)。配列のプロパティ(heroines)が定められ、データはメソッド(getHeroines())により納められるかたちです。ただし、Array.slice()メソッドが件数を4つに絞っています。そして、コンポーネントがつくられたとき、ngOnInit()からメソッドが呼び出されるのです。

src/app/dashboard/dashboard.component.ts

import {Heroine} from '../heroine';
import {HeroineService} from '../heroine.service';

export class DashboardComponent implements OnInit {
	heroines: Heroine[] = [];
	// constructor() { }
	constructor(private heroineService: HeroineService) { }
	ngOnInit(): void {
		this.getHeroines();
	}
	getHeroines():void {
		this.heroineService.getHeroines()
		.subscribe(heroines => this.heroines = heroines.slice(0, 4));
	}
}

コンポーネント(dashboard.component)のテンプレートとCSSファイルは、以下のコード002のとおりです。テンプレートはngForディレクティブで、プロパティ(heroines)の配列要素の数だけ<a>要素を加えます。リンク先はまだ定められていません。改められたTypeScriptコードも併せて掲げておきます。

コード002■ダッシュボードコンポーネントのコード

src/app/dashboard/dashboard.component.html

<h3>トップヒロイン</h3>
<div class="grid grid-pad">
	<a *ngFor="let heroine of heroines" class="col-1-4">
		<div class="module heroine">
			<h4>{{heroine.name}}</h4>
		</div>
	</a>
</div>

src/app/dashboard/dashboard.component.css

[class*='col-'] {
	float: left;
	padding-right: 20px;
	padding-bottom: 20px;
}
[class*='col-']:last-of-type {
	padding-right: 0;
}
a {
	text-decoration: none;
}
*, *::after, *::before {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;
}
h3 {
	text-align: center; margin-bottom: 0;
}
h4 {
	position: relative;
}
.grid {
	margin: 0;
}
.col-1-4 {
	width: 25%;
}
.module {
	padding: 20px;
	text-align: center;
	color: #eee;
	max-height: 120px;
	min-width: 120px;
	background-color: #607D8B;
	border-radius: 2px;
}
.module:hover {
	background-color: #EEE;
	cursor: pointer;
	color: #607d8b;
}
.grid-pad {
	padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
	padding-right: 20px;
}
@media (max-width: 600px) {
	.module {
		font-size: 10px;
		max-height: 75px;
	}
}
@media (max-width: 1024px) {
	.grid {
		margin: 0;
	}
	.module {
		min-width: 60px;
	}
}

src/app/dashboard/dashboard.component.ts

import {Component, OnInit} from '@angular/core';
import {Heroine} from '../heroine';
import {HeroineService} from '../heroine.service';
@Component({
	selector: 'app-dashboard',
	templateUrl: './dashboard.component.html',
	styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
	heroines: Heroine[] = [];
	constructor(private heroineService: HeroineService) { }
	ngOnInit(): void {
		this.getHeroines();
	}
	getHeroines():void {
		this.heroineService.getHeroines()
		.subscribe(heroines => this.heroines = heroines.slice(0, 4));
	}
}

05 ナビゲーションにダッシュボードへのリンクを加える

ベージのナビゲーションに、ダッシュボードへのリンクを加えます。リスト表示コンポーネントへのリンクと同じく、つぎのようにルーテイングモジュール(app-routing.module)の定数(routes)に配列要素としてプロパティpath('dashboard')とcomponent(DashboardComponent)が与えられたオブジェクトを加えるのです。さらに、空のパス('')つまりURLがルート('/')のときの転送先がredirectToプロパティで定められます。これで、はじめにrouter-outletディレクティブの要素が空で示されることはなくなります。なお、pathMatchプロパティの値'full'は、パスが完全に空('')のときのみ転送される指定です(「Matching Strategy」参照)。

src/app/app-routing.module.ts

import {DashboardComponent} from './dashboard/dashboard.component';

const routes: Routes = [
	{path: '', redirectTo: '/dashboard', pathMatch: 'full'},
	{path: 'dashboard', component: DashboardComponent},

];

あとは、親コンポーネント(app.component)のナビゲーションに、前述で定めたパス("/dashboard")をルーテイングのリンクとして、つぎのようにrouterLinkディレクティブに与えるだけです。これでアプリケーションをブラウザで開くと、ルートがダッシュボードにリダイレクトされます(図004)。そして、ナビゲーションのリンクで、リスト表示とダッシュボードを切り替えることもできるのです。以下のコード003に、ルーティングのモジュール(app-routing.module)のTypeScriptコードと親コンポーネント(app.component)のテンプレート、およびルーティング(AppRoutingModule)やダッシュボード(DashboardComponent)のクラスが組み込まれたアプリケーション(app.module)のTypeScriptコードをまとめました。Plunkerのサンプルコードは「Angular 5 Example - Tour of Heroines 06」をご覧ください。

src/app/app.component.html

<nav>
	<a routerLink="/dashboard">ダッシュボード</a>
	<a routerLink="/heroines">ヒロインたち</a>
</nav>

図004■はじめにダッシュボードが表示される

図004

コード003■ルーティングのモジュールと親コンポーネントのテンプレートおよびアプリケーションのTypeScriptコード

src/app/app-routing.module.ts

import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {DashboardComponent} from './dashboard/dashboard.component';
import {HeroinesComponent} from './heroines/heroines.component';
const routes: Routes = [
	{path: '', redirectTo: '/dashboard', pathMatch: 'full'},
	{path: 'dashboard', component: DashboardComponent},
	{path: 'heroines', component: HeroinesComponent}
];
@NgModule({
	imports: [RouterModule.forRoot(routes)],
	exports: [RouterModule]
})
export class AppRoutingModule {}

src/app/app.component.html

<h1>{{title}}</h1>
<nav>
	<a routerLink="/dashboard">ダッシュボード</a>
	<a routerLink="/heroines">ヒロインたち</a>
</nav>
<router-outlet></router-outlet>
<app-messages></app-messages>

src/app/app.module.ts

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {AppComponent} from './app.component';
import {HeroinesComponent} from './heroines/heroines.component';
import {HeroineDetailComponent} from './heroine-detail/heroine-detail.component';
import {HeroineService} from './heroine.service';
import {MessagesComponent} from './messages/messages.component';
import {MessageService} from './message.service';
import {AppRoutingModule} from './app-routing.module';
import {DashboardComponent} from './dashboard/dashboard.component';
@NgModule({
	declarations: [
		AppComponent,
		HeroinesComponent,
		HeroineDetailComponent,
		MessagesComponent,
		DashboardComponent
	],
	imports: [
		BrowserModule,
		FormsModule,
		AppRoutingModule
	],
	providers: [HeroineService, MessageService],
	bootstrap: [AppComponent]
})
export class AppModule {}


作成者: 野中文雄
作成日: 2018年1月29日


Copyright © 2001-2018 Fumio Nonaka.  All rights reserved.