Angularの公式チュートリアル:第6章「Routing」

Tour of Heroesアプリに、新たな要件を加えます:

  • ダッシュボードのビューを追加
  • ヒーロー一覧とダッシュボードの間を遷移可能にする
  • どちらかのビューでユーザがヒーロー名をクリックすると、そのヒーローの詳細ビューに遷移する
  • メールの中のディープリンクをクリックすると、特定のヒーローの詳細ビューを開く

これらを追加すると、次のようにアプリの中をナビゲーション可能になります:

https://angular.io/generated/images/guide/toh/nav-diagram.png

この新たな要件を満たす為に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>要素を追加します
  • AppModuleHeroesComponentをimportし、かつ、declarationsHeroesComponentを追加します
  • AppModuleproviders配列にHeroServiceを追加します。
  • HeroesComponentproviders配列から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と実行してみてください。無事、アプリケーションが動くはずです。

(続く)