Angular2の始め方。Angular2 公式チュートリアル – Multiple Components(簡単な和訳)
2017.04.03
この記事は最終更新日から1年以上が経過しています。
MULTIPLE COMPONENTS
こちらのページは、こちらのページの簡単な和訳です。
Angular2 tutorial | MULTIPLE COMPONENTS
前回
Angular2の始め方。Angular2 公式チュートリアル – Master/Detail(簡単な和訳)
その他
Angular2の始め方。Angular2 公式チュートリアル – SETUP FOR LOCAL DEVELOPMENT(簡単な和訳)Angular2の始め方。Angular2 公式チュートリアル – Introduction(簡単な和訳)
Angular2の始め方。Angular2 公式チュートリアル – The Hero Editor(簡単な和訳)
私たちのアプリは成長してきています。
コンポーネントを再利用し、データをコンポーネントに渡し、より再利用可能なリソースを作成するためのユースケースがでてきております。
ヒーローのリストをヒーローの詳細から分離して、詳細コンポーネントを再利用可能にしましょう。
Run the live example for this part.
Where We Left Off
ヒーローのツアーを続ける前に、次の構造を持っていることを確認しましょう。そうでない場合は、前の章に戻って行ってください。
angular-tour-of-heroes ├──src │ ├──app │ │ ├──app.component.ts │ │ └──app.module.ts │ ├──main.ts │ ├──index.html │ ├──styles.css │ ├──systemjs.config.js │ └──tsconfig.json ├──node_modules ... └──package.json
Make a hero detail component
hero-detail.component.tsという名前のファイルを app /フォルダーに追加します。
このファイルは新しいHeroDetailComponentを保持します。
ファイル名とコンポーネント名は、スタイルガイドに記載されている標準に従います。
コンポーネントクラス名は、キャメルケースの大文字で書かれ、 “Component”という単語で終わるべきです。
主人公の詳細コンポーネントクラスはHeroDetailComponentです。
コンポーネントファイルの名前は、ダッシュ記号で綴る必要があります。各単語はダッシュで区切り、.component.tsで終わります。
HeroDetailComponentクラスはhero-detail.component.tsファイルに入れられます。
次のようにHeroDetailComponentの書き込みを開始します。
app/hero-detail.component.ts (initial version)
import { Component } from '@angular/core'; @Component({ selector: 'hero-detail', }) export class HeroDetailComponent { }
コンポーネントを定義するには、常にコンポーネントシンボルをインポートします。
@Componentデコレータは、コンポーネントのメタデータを提供します。 CSSセレクタ名、hero-detailは、親コンポーネントのテンプレート内このコンポーネントを特定する要素タグにマッチします。このチュートリアルページの終わり近くに、あなたはAppComponentテンプレートに
常に他の場所にimportするため、コンポーネントクラスをexportしてください。
Hero detail template
ヒーロー詳細ビューを HeroDetailComponentに移動するには、ヒーロー詳細コンテンツをAppComponentテンプレートの下部から切り取り、@Componentメタデータの新しいテンプレートプロパティに貼り付けます。
HeroDetailComponentには、選択されたヒーローではなく、ヒーローがあります。 “selectedHero”という単語をテンプレートのどこにでも置いて “hero”という単語に置き換えます。完了したら、新しいテンプレートは次のようになります。
src/app/hero-detail.component.ts (template)
@Component({ selector: 'hero-detail', 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> ` })
Add the hero property
HeroDetailComponentテンプレートは、コンポーネントのheroプロパティにバインドされます。
そのようなプロパティをHeroDetailComponentクラスに次のように追加します。
src/app/hero-detail.component.ts (hero property)
hero: Hero;
ヒーロープロパティはヒーローのインスタンスとしてタイプされます。 Heroクラスはまだapp.component.tsファイルにあります。
今、Heroクラスを参照する必要がある2つのコンポーネントがあります。
Angularスタイルガイドでは、ファイルごとに1つのクラスを推奨します。
Heroクラスをapp.component.tsから独自のhero.tsファイルに移動します。
src/app/hero.ts
export class Hero { id: number; name: string; }
Heroクラスが独自のファイルになったので、AppComponentと、HeroDetailComponentはそれをインポートする必要があります。
app.component.tsファイルと、hero-detail.component.tsファイルの上部に次のimport文を追加します。
import { Hero } from './hero';
The hero property is an input property
このページの後半では、親AppComponentは、選択されたヒーローをHeroDetailComponentのヒーロープロパティにバインドして表示するヒーローを子供のHeroDetailComponentに伝えます。バインディングは次のようになります。
<hero-detail [hero]="selectedHero"></hero-detail>
ヒーロープロパティの周りに等号(=)の左側に角括弧を置くと、プロパティバインディング式のターゲットになります。
ターゲットバインディングプロパティを入力プロパティに宣言する必要があります。
それ以外の場合、Angularはバインディングを拒否し、エラーをスローします。
まず、入力シンボルを含めるために @angular/core のimport文を修正します。
import { Component, Input } from '@angular/core';
その後、ヒーローは、前にインポートした@Inputデコレータを前に置いて、入力プロパティであることを宣言します。
src/app/hero-detail.component.ts (excerpt)
@Input() hero: Hero;
““
属性の詳細については、属性ディレクティブのページを参照してください。
““
これで終了となります。ヒーロープロパティはHeroDetailComponentクラスの唯一のものです。
export class HeroDetailComponent { @Input() hero: Hero; }
それが行うことは、ヒーロー入力プロパティでヒーローオブジェクトを受け取った後、そのテンプレートでそのプロパティにバインドすることだけです。
ここには完全なHeroDetailComponentがあります。
src/app/hero-detail.component.ts
import { Component, Input } from '@angular/core'; import { Hero } from './hero'; @Component({ selector: 'hero-detail', 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> ` }) export class HeroDetailComponent { @Input() hero: Hero; }
Declare HeroDetailComponent in the AppModule
すべてのコンポーネントは、1つの唯一のAngularモジュールで宣言する必要があります。
エディタでapp.module.tsを開き、参照できるようにHeroDetailComponentをインポートします。
src/app/app.module.ts
import { HeroDetailComponent } from './hero-detail.component';
HeroDetailComponentをモジュールの宣言配列に追加します。
src/app/app.module.ts
declarations: [ AppComponent, HeroDetailComponent ],
一般に、宣言配列には、モジュールに属するアプリケーションコンポーネント、パイプ、およびディレクティブのリストが含まれています。
他のコンポーネントがモジュールを参照するには、そのモジュール内でコンポーネントを宣言する必要があります。
このモジュールは、AppComponentと、HeroDetailComponentの2つのアプリケーションコンポーネントのみを宣言します。
““`
NgModulesガイドのAngularモジュールの詳細。
““`
Add the HeroDetailComponent to the AppComponent
AppComponentはまだ master/detail ビューです。
それはテンプレートのその部分を切り取る前に、ヒーローの詳細を独自に表示することでした。
今度はHeroDetailComponentに委譲します。
hero-detailは、HeroDetailComponentメタデータのCSSセレクタであることを思い出してください。
これは、HeroDetailComponentを表す要素のタグ名です。
ヒーロー詳細ビューを使用していた、AppComponentテンプレートの下部に
要素を追加します。
AppComponentのselectedHeroプロパティを、 HeroDetailComponentのヒーロープロパティにバインドして、マスターAppComponentをHeroDetailComponentと調整します。
app.component.html (excerpt)
<hero-detail [hero]="selectedHero"></hero-detail>
selectedHeroが変更されるたびに、HeroDetailComponentは新しいヒーローを取得して表示します。
修正されたAppComponentテンプレートは、次のようになります。
app.component.ts (excerpt)
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> <hero-detail [hero]="selectedHero"></hero-detail> `,
What changed?
以前のように、ユーザーがヒーロー名をクリックするたびに、ヒーローの詳細がヒーローリストの下に表示されます。
しかし、今、HeroDetailViewはそれらの詳細を提示しています。
元のAppComponentを2つのコンポーネントにリファクタリングすることで、現状も今後にも利益がでます。
・AppComponentの責任を軽減してAppComponentを単純化しました。
・親AppComponentに触れることなく、HeroDetailComponentを豊かなヒーローエディタに拡張させることができます。
・ヒーロー詳細ビューに触れることなくAppComponentを拡張させることができます。
・将来の親コンポーネントのテンプレートでHeroDetailComponentを再利用することができます。
Review the app structure
次の構造を持っていることを確認します。
angular-tour-of-heroes ├──src │ ├──app │ │ ├──app.component.ts │ │ ├──app.module.ts │ │ ├──hero.ts │ │ └──hero-detail.component.ts │ ├──main.ts │ ├──index.html │ ├──styles.css │ ├──systemjs.config.js │ └──tsconfig.json ├──node_modules ... └──package.json
このページで解説するコードファイルは次のとおりです。
src/app/hero-detail.component.ts
import { Component, Input } from '@angular/core'; import { Hero } from './hero'; @Component({ selector: 'hero-detail', 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> ` }) export class HeroDetailComponent { @Input() hero: Hero; }
src/app/app.component.ts
import { Component } from '@angular/core'; import { Hero } from './hero'; const HEROES: Hero[] = [ { id: 11, name: 'Mr. Nice' }, { id: 12, name: 'Narco' }, { id: 13, name: 'Bombasto' }, { id: 14, name: 'Celeritas' }, { id: 15, name: 'Magneta' }, { id: 16, name: 'RubberMan' }, { id: 17, name: 'Dynama' }, { id: 18, name: 'Dr IQ' }, { id: 19, name: 'Magma' }, { id: 20, name: 'Tornado' } ]; @Component({ selector: 'my-app', 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> <hero-detail [hero]="selectedHero"></hero-detail> `, styles: [` .selected { background-color: #CFD8DC !important; color: white; } .heroes { margin: 0 0 2em 0; list-style-type: none; padding: 0; width: 15em; } .heroes li { cursor: pointer; position: relative; left: 0; background-color: #EEE; margin: .5em; padding: .3em 0; height: 1.6em; border-radius: 4px; } .heroes li.selected:hover { background-color: #BBD8DC !important; color: white; } .heroes li:hover { color: #607D8B; background-color: #DDD; left: .1em; } .heroes .text { position: relative; top: -3px; } .heroes .badge { display: inline-block; font-size: small; color: white; padding: 0.8em 0.7em 0 0.7em; background-color: #607D8B; line-height: 1em; position: relative; left: -1px; top: -4px; height: 1.8em; margin-right: .8em; border-radius: 4px 0 0 4px; } `] }) export class AppComponent { title = 'Tour of Heroes'; heroes = HEROES; selectedHero: Hero; onSelect(hero: Hero): void { this.selectedHero = hero; } }
src/app/hero.ts
export class Hero { id: number; name: string; }
app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { HeroDetailComponent } from './hero-detail.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent, HeroDetailComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
The road you’ve travelled
このページであなたが達成したことは次のとおりです。
・再利用可能なコンポーネントを作成しました。
・コンポーネントが入力を受け入れる方法を学びました。
・必要なアプリケーション指令をAngularモジュールで宣言することを学びました。
・NgModuleデコレータの宣言配列にディレクティブをリストしました。
・親コンポーネントを子コンポーネントにバインドする方法を学びました。
・あなたのアプリはこのlive example / downloadable example.のように見えるはずです。
The road ahead
Tour of Heroesアプリは、共有コンポーネントで再利用可能ですが、そのモックデータはまだAppComponent内でハードコーディングされています。
それは持続可能ではありません。
データアクセスは別のサービスにリファクタリングし、データを必要とするコンポーネント間で共有する必要があります。
次のチュートリアルページでサービスを作成する方法を学びます。