前回の投稿Angluar2のクイックスタートとチュートリアルを実施 - その3の続きです。
前回作成したソースを使用します。
本投稿の参照元(英語)
(バージョンが異なりますが、大きな影響はないと思います。)
Multiple Components - ts
本章で学ぶこと
以下を学習します。
- 再使用可能なように、コンポーネントを分ける
- 入力(引数のような)を受け取るコンポーネントの作り方を学ぶ
-
NgModuleデコレータにdeclarations配列を追加する - コンポーネント同士の親子バインドを学ぶ
実行結果
本章を完了すると以下リンク先のようなものが出来上がります。
見た目は前回のアプリと変わっていません。
live-examples
事前準備
以下のコマンドによりサーバの起動を行います。プログラムの変更が即座にブラウザに反映されます。(サーバを落としていなければ不要です。)
cd angular2-tour-of-heroes
npm start
ヒーロー詳細コンポーネントの作成
前章まで、ヒーローの一覧とヒーローの詳細を同じコンポーネントにしていましたが、一つのファイルが大きくなりすぎると、メンテナンスの難度が上がります。
また、単一責任の原則(@gomi_ningenさんの記事)を犯しています。
ヒーロー詳細部分の分割
新たにファイルapp/hero-detail.component.tsを作成して、そこにヒーローの詳細を移します。
import { Component, Input } from '@angular/core';
@Component({
selector: 'my-hero-detail',
})
export class HeroDetailComponent {
}
@angular/coreのComponentとInputをインポートします。@Componentデコレータで、この部品の要素名my-hero-detailを指定します。Inputはあと説明します。
また、後ほどapp/app.component.tsでこのファイルを使用します。
ヒーロー詳細テンプレート
現時点ではヒーローの一覧とヒーローの詳細がAppComponent内で同居しています。AppComponentのテンプレートから、ヒーローの詳細を表示する部分を切り取りし、HeroDetailComponentへ貼り付けましょう。AppComponentでselectedHeroプロパティとしていた部分はHeroDetailComponentではheroプロパティとしてください。
結果app/hero-detail.component.tsのtemplateは以下の様になります。
template: `
<div *ngIf="hero">
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="hero.name" placeholder="name"/>
</div>
</div>
`
ヒーロープロパティの追加
HeroDetailComponentにもHeroクラスを持たせる必要がありますが未定義です。Heroクラスは、HeroComponentに定義されています。まずは、Heroプロパティをapp/hero.tsに移し替えます。
export class Hero {
id: number;
name: string;
}
そして、app.component.tsとhero-detail.component.tsで、hero.tsをインポートします。
import { Hero } from './hero';
HeroDetailComponentは、HeroComponentにより表示されます。HeroComponentではユーザが選択したヒーローはselectedHeroプロパティに格納されます。
以下の様にAppComponentのselectedHeroをHeroDetailComponentのhero
プロパティにバインドします。
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
ここでのmy-hero-detailは、HeroDetailComponentの@Componentデコレータで定義したセレクター、heroはHeroDetailComponentのheroプロパティです。
[バインド先]="バインド元"の形で、プロパティの値を渡します。
詳細はこちら(英語)
heroプロパティを入力にする方法は2つありますが、ここでは@Inputデコレータによる、アノテーションでそれを実現します。
HeroDetailComponentクラスを以下の様に変更します。
export class HeroDetailComponent {
@Input()
hero: Hero;
}
@Inputデコレータの詳細はこちら(英語)
AppModuleの更新
AppModuleは、このアプリのメインモジュールです。このモジュールにHeroDetailComponentを使用することを宣言します。
import { HeroDetailComponent } from './hero-detail.component';
つぎに@NgModuleデコレータのdeclarations配列にHeroDetailComponentを追加します。declarationsにはこのアプリで使用する全てのcomponent, pipe, directiveを定義します。
@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
HeroDetailComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
AppComponentの更新
アプリはHeroDetailComponentを認識できるようになりました。AppComponentのヒーロー詳細表示部分を削除し、以下の様に変更します。
template: `
<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
`,
これで、ヒーロー詳細の移行は完了です。
本章は以上です。次章ではサービスの作成方法を説明します。