Angular2の始め方。Angular2 公式チュートリアル – Master/Detail(簡単な和訳)
2017.01.20
この記事は最終更新日から1年以上が経過しています。
MASTER/DETAIL
こちらのページは、こちらのページの簡単な和訳です。
Angular2 tutorial | MASTER/DETAIL
その他
Angular2の始め方。Angular2 公式チュートリアル – Introduction(簡単な和訳)
Angular2の始め方。Angular2 公式チュートリアル – The Hero Editor(簡単な和訳)
私たちの物語はより多くの英雄を必要とします。
ヒーローのアプリを拡張してヒーローのリストを表示し、ユーザーがヒーローを選択できるようにし、ヒーローの詳細を表示します。
このパーツのライブサンプルを実行します。
ヒーローのリストを表示するために必要なものを用意しましょう。まず、ヒーローのリストが必要です。
それらのヒーローをビューのテンプレートに表示したいので、そのヒーローを行う方法が必要です。
Run the live example
Where We Left Off
ヒーローツアーのパート2を続行する前に、パート1の後に次の構造を持っていることを確認してください。そうでない場合は、パート1に戻って、逃したものを見つけ出す必要があります。
angular-tour-of-heroes ├── app │ ├── app.component.ts │ ├── app.module.ts │ └── main.ts ├── node_modules ... ├── index.html ├── package.json ├── styles.css ├── systemjs.config.js └── tsconfig.json
Keep the app transpiling and running
TypeScriptコンパイラを起動し、変更を監視してからサーバーを起動する必要があります。これを入力するには
npm start
これにより、Tour of Heroesを引き続き構築しながら、アプリケーションを実行し続けることができます。
Displaying Our Heroes
Creating heroes
10人のヒーローの配列を作りましょう。
app.component.ts (hero array)
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' } ];
Exposing heroes
AppComponentにバインディングする、ヒーローのpublicプロパティを作成しましょう。
app.component.ts (hero array property)
heroes = HEROES;
ヒーローの型を定義する必要はありませんでした。 TypeScriptはHEROES配列から推論できます。
—
ここでは、このコンポーネントクラスでヒーローリストを定義できました。
しかし、最終的に我々はデータサービスから英雄を得ようとしております。なので、ヒーローデータをクラスの実装から最初から分離するのが理にかなっています。
—
Displaying heroes in a template
私たちのコンポーネントはヒーローを持っています。私たちのテンプレートにリストを作成して表示してみましょう。タイトルの下にヒーローの詳細の上に次のHTMLの塊を挿入します。
app.component.ts (heroes template)
<h2>My Heroes</h2> <ul class="heroes"> <li> <!-- each hero goes here --> </li> </ul>
今、私たちはヒーローで満たすことのできるテンプレートを用意しています。
Listing heroes with ngFor
私たちは、コンポーネント内のヒーローの配列をテンプレートにバインドし、反復処理して個々に表示したいと考えています。
これを行うにはAngularの助けが必要です。これをステップごとに行っていきましょう。
まず、組み込みディレクティブ* ngForを追加して<li>要素を変更します。
app.component.ts (ngFor)
<li *ngFor="let hero of heroes">
——-
ngForの前にある先頭のアスタリスク(*)は、この構文の重要な部分です。
——-
—
マルチライン文字列に対してはバックティック記法を再度使用しています。
それは多くの記述となってしまいます。
ここに示すようにインラインで配置することも、独自のファイルに移動してコンポーネントを簡単にコーディングすることもできます。
後の章でこれを行います。今のところ圧延を続けましょう。
コンポーネントにスタイルを割り当てるとき、そのコンポーネントはそのコンポーネントに適用されます。
私たちのスタイルはAppComponentにのみ適用され、外側のHTMLには “リーク”しません。
ヒーローを表示するテンプレートは次のようになります。
—
ヒーローのテンプレート変数を使用してヒーローのプロパティを表示する、 <li>要素の間に、いくつかのコンテンツを挿入します。
app.component.ts (styled heroes)
<li *ngFor="let hero of heroes"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li>
ブラウザを更新すると、ヒーローのリストが表示されます。
Styling our heroes
ヒーローの私達のリストはかなりかわいらしく見えます。
私たちは、ユーザーがどのようなヒーローを選んでいるのか、また どのヒーローが選択されているのかを視覚的に明確にしたいと考えています。
@Componentデコレータのstylesプロパティを次のCSSクラスに設定することによって、コンポーネントにいくつかのスタイルを追加しましょう。
app.component.ts (styles)
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; } `]
複数行の文字列に対してはバックティック表記法を再度使用しています。
ここに示すようにインラインで配置することも、独自のファイルに移動してコンポーネントを簡単にコーディングすることもできます。
後の章でこれを行います。今のところこのまま続けましょう。
コンポーネントにスタイルを割り当てるとき、そのコンポーネントはそのコンポーネントに適用されます。
私たちのスタイルはAppComponentにのみ適用され、外側のHTMLには影響しません。
ヒーローを表示するテンプレートは次のようになります。
app.component.ts (styled heroes)
<h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul>
Selecting a Hero
ヒーローのリストがあり、私たちのアプリにはひとつのヒーローが表示されています。
リストとシングルヒーローは決してつながっていません。
ユーザーはリストからヒーローを選択して、選択したヒーローを詳細ビューに表示させます。
このUIパターンは、「master-detail」として広く知られています。
私たちの場合、「master」は、ヒーローリストであり、「detail」は選択されたヒーローです。
クリックイベントにバインドされた、selectedHeroコンポーネントプロパティを使用して、「master」を「detail」に接続しましょう。
Click event
- Angleイベントのバインドをclickイベントに挿入して、<li>を修正します。app.component.ts (template excerpt)
<li *ngFor="let hero of heroes" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li>
イベントバインディングに焦点を当てる
(click)="onSelect(hero)"
括弧は
- 要素のクリックイベントをターゲットとして識別します。等号の右側にある式はAppComponentメソッドのonSelect()を呼び出し、テンプレート入力変数heroを引数として渡します。
これはngForで以前定義したのと同じヒーロー変数です。
—
UserInputとTemplating Syntaxの章でイベントバインドの詳細を学んでください。
—Add the click handler
私たちのイベントバインディングは、まだ存在しないonSelectメソッドを指します。
このメソッドをコンポーネントに追加します。
その行うには、何をすべきでしょうか?
コンポーネントが選択したヒーローを、ユーザーがクリックしたヒーローに設定する必要があります。
私たちのコンポーネントには、まだ「選ばれたヒーロー」はありません。
私たちはそこから始めます。
Expose the selected hero
AppComponentの静的ヒーロープロパティはもう必要ありません。
これを単純なselectedHeroプロパティに置き換えます:
app.component.ts (selectedHero)
selectedHero: Hero;
ユーザーがヒーローを選ぶ前に選んだヒーローは誰も選んではいけないので、ヒーローと同じようにselectedHeroを初期化しないことにしました。
selectedHeroプロパティをユーザーがクリックしたヒーローに設定するonSelectメソッドを追加します。
app.component.ts (onSelect)
onSelect(hero: Hero): void { this.selectedHero = hero; }
app.component.ts (template excerpt)
<h2>{{selectedHero.name}} details!</h2> <div><label>id: </label>{{selectedHero.id}}</div> <div> <label>name: </label> <input [(ngModel)]="selectedHero.name" placeholder="name"/> </div>
Hide the empty detail with ngIf
アプリが読み込まれるとヒーローのリストが表示されますが、ヒーローは選択されません。
selectedHeroは未定義です。そのため、ブラウザのコンソールで次のエラーが表示されます。
—
EXCEPTION: TypeError: Cannot read property ‘name’ of undefined in [null]
—テンプレートにselectedHero.nameが表示されていることを忘れないでください。
selectedHero自体が未定義であるため、このnameプロパティは存在しません。
選ばれたヒーローが存在するまで、ヒーローの詳細をDOMから外しておくことで、この問題に対処します。
テンプレートのHTMLヒーローの詳細コンテンツを
で囲みます。次にngIf組込みディレクティブを追加し、コンポーネントのselectedHeroプロパティに設定します。
app.component.ts (ngIf)<div *ngIf="selectedHero"> <h2>{{selectedHero.name}} details!</h2> <div><label>id: </label>{{selectedHero.id}}</div> <div> <label>name: </label> <input [(ngModel)]="selectedHero.name" placeholder="name"/> </div> </div>
—
ngIfの前にある先頭のアスタリスク(*)はこの構文の重要な部分です。
—selectedHeroがない場合、ngIfディレクティブはヒーローの詳細HTMLをDOMから削除します。
ヒーローの詳細要素はなく、拘束力はありません。
ユーザーがヒーローを選択すると、selectedHeroは「true」になり、ngIfはヒーローの詳細コンテンツをDOMに入れ、ネストされたバインディングを評価します。
—
ngIfとngForは、DOMの一部の構造を変更できるため、構造ディレクティブと呼ばれます。言い換えれば、AngularはDOM内のコンテンツを表示する方法に構造を与えます。ngIf、ngFor、その他の構造ディレクティブの詳細については、Structural DirectivesとTemplate Syntaxの章を参照してください。
—ブラウザが更新され、英雄のリストが表示されますが、選択されたヒーローの詳細は表示されません。
ngIfは、selectedHeroが定義されていない限り、DOMからそれを保持します。
リスト内のヒーローをクリックすると、選択されたヒーローがヒーローの詳細に表示されます。私たちが期待するようにすべてが働いています。
Styling the selection
私たちは下記の詳細エリアで選択されたヒーローを見ますが、上記のヒーローをすぐに見つけることはできません。
選択したCSSクラスをマスターリストの適切な
- に適用することで、修正できます。たとえば、ヒーローリストからMagnetaを選択すると、ここに示すように微妙な背景色を付けることで視覚的にポップアウトさせることができます。
選択したクラスのクラスのプロパティバインディングをテンプレートに追加します。
これを、現在選択されているヒーローとヒーローを比較する式に設定します。
キーは、CSSクラス(選択済み)の名前です。 2つのヒーローが一致する場合はtrue、そうでない場合はfalseです。
「ヒーローが一致すれば選択したクラスを適用し、そうでなければ削除する」と言っています。
app.component.ts (setting the CSS class)
[class.selected]="hero === selectedHero"
テンプレートでclass.selectedが角かっこ([])で囲まれていることに注目してください。
これは、プロパティバインディングの構文です。
データがデータソース(expression hero === selectedHero)からクラスのプロパティへ一方向に流れるバインディングです。
app.component.ts (styling each hero)
<li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li>
—
Learn more about property bindings in the Template Syntax chapter.
—ブラウザがアプリをリロードします。私たちは主人公Magnetaを選択し、その選択は背景色によって明確に識別されます。
私たちは別のヒーローを選択し、そのヒーローに忠実な色の切り替えを行います。
ここには完全なapp.component.tsがあります
app.component.ts
import { Component } from '@angular/core'; export class Hero { id: number; name: string; } 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> <div *ngIf="selectedHero"> <h2>{{selectedHero.name}} details!</h2> <div><label>id: </label>{{selectedHero.id}}</div> <div> <label>name: </label> <input [(ngModel)]="selectedHero.name" placeholder="name"/> </div> </div> `, 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; } }
The Road We’ve Travelled
この章では、次のようなことを達成しました。
・ 私たちのヒーローツアーでは、選択可能なヒーローのリストが表示されるようになりました
・ ヒーローを選んでヒーローの詳細を表示する機能を追加しました
・ 組み込みディレクティブngIfとngForをコンポーネントのテンプレートで使用する方法を学びました
Run the live example for this part.
The Road Ahead
私たちのヒーローツアーは成長しましたが、それは完全ではありません。
アプリ全体を単一のコンポーネントにまとめることはできません。私たちはそれをサブコンポーネントに分解し、次の章で学ぶように一緒に働くように教える必要があります。
次のSTEP
Angular2の始め方。Angular2 公式チュートリアル – Multiple Components(簡単な和訳)