Tour of Heroesアプリに、新たな要件を加えます:
- ダッシュボードのビューを追加
- ヒーロー一覧とダッシュボードの間を遷移可能にする
- どちらかのビューでユーザがヒーロー名をクリックすると、そのヒーローの詳細ビューに遷移する
- メールの中のディープリンクをクリックすると、特定のヒーローの詳細ビューを開く
これらを追加すると、次のようにアプリの中をナビゲーション可能になります:
この新たな要件を満たす為にAngularのルータをアプリに追加します。
進め方
次のように進めます:
AppComponent
にナビゲーションのみを担当させます- 現在の
AppComponent
のヒーローに関する実装を別の、HeroesComponent
に分割します。 - ルーティングを追加します
- 新たに
DashboardComponent
を作ります - ナビゲーションにダッシュボードを組み込みます
AppComponentの分割
現時点のアプリはAppComponent
を読み込み即座にヒーロー一覧を表示します。
変更後のアプリはシェルに対してビューの選択肢(ダッシュボードとヒーロー一覧)を与え、そのうちの一つをデフォルトとして表示します。
AppComponent
はナビゲーションのみを担当すべきなので、ヒーローに関する実装をAppComponent
からHeroesComponent
に移動します。
HeroesComponentについて
AppComponent
はすでにヒーローに特化していますので、AppComponent
からコードを移動するのはではなくHeroesComponent
にリネームし、新たにAppComponent
を作成しましょう。
次を実行してください:
app.component.ts
ファイルをheroes.component.ts
にリネームAppComponent
クラスをHeroesComponent
クラスにリネーム(heroes.component.ts
の中のみ)app-root
セレクタをmy-heroes
セレクタにリネームします
変更後のheroes.component.ts
import { Component, OnInit } from '@angular/core'; import { Hero } from './hero'; import { HeroService } from './hero.service'; @Component({ selector: 'my-heroes', template: `<h2>私のヒーロー一覧</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" (click)="onSelect(hero)" [class.selected]="hero === selectedHero"> <span class="badge">{{hero.id}}</span>{{hero.name}} </li> </ul> <hero-detail [hero]="selectedHero"></hero-detail> `, styleUrls: ['./app.component.css'], providers: [] }) export class HeroesComponent implements OnInit { selectedHero: Hero; heroes: Hero[]; onSelect(myhero: Hero): void { this.selectedHero = myhero; } constructor (private heroService: HeroService) { } ngOnInit(): void { this.getHeroes(); } getHeroes(): void { this.heroService.getHeroes().then(heroes => this.heroes = heroes); } }
AppComponentを作成する
新しく作るAppComponent
はアプリケーションのシェルにすぎません。画面上部にはナビゲーションがあり、その下には表示領域があります。
次の手順を実行してください:
src/app/app.component.ts
というファイルを作成しますAppComponent
クラスを作成しexportします- クラス定義の上に
@Component
デコレータを記述し、セレクタとしてmy-app
を指定します HeroesComponent
から以下の部分をAppComponent
に移動します:- クラス属性の
title
@Component
のテンプレートの中の<h1>
(title
とのバインドを含みます)- テンプレートの見出しの下に
<my-heroes>
要素を追加します AppModule
にHeroesComponent
をimportし、かつ、declarations
にHeroesComponent
を追加しますAppModule
のproviders
配列にHeroService
を追加します。HeroesComponent
のproviders
配列からHeroService
を削除しますAppComponent
に必要なimport
文を記述します
編集後のapp.component.ts
import { Component } from '@angular/core'; @Component ({ selector: 'app-root', template: `<h1>{{title}}</h1> <my-heroes></my-heroes> ` }) export class AppComponent { title = 'Tour of Heroes'; }
編集後の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 { HeroDetailComponent } from './hero-detail.component'; import { HeroesComponent } from './heroes.component'; import { HeroService } from './hero.service'; @NgModule({ declarations: [ AppComponent, HeroDetailComponent, HeroesComponent ], imports: [ BrowserModule, FormsModule ], providers: [HeroService], bootstrap: [AppComponent] }) export class AppModule { }
編集後のheroes.component.ts
import { Component, OnInit } from '@angular/core'; import { Hero } from './hero'; import { HeroService } from './hero.service'; @Component({ selector: 'my-heroes', template: `<h2>私のヒーロー一覧</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" (click)="onSelect(hero)" [class.selected]="hero === selectedHero"> <span class="badge">{{hero.id}}</span>{{hero.name}} </li> </ul> <hero-detail [hero]="selectedHero"></hero-detail> `, styleUrls: ['./app.component.css'], providers: [] }) export class HeroesComponent implements OnInit { selectedHero: Hero; heroes: Hero[]; onSelect(myhero: Hero): void { this.selectedHero = myhero; } constructor (private heroService: HeroService) { } ngOnInit(): void { this.getHeroes(); } getHeroes(): void { this.heroService.getHeroes().then(heroes => this.heroes = heroes); } }
テスト
この時点でnpm start
と実行してみてください。無事、アプリケーションが動くはずです。
(続く)