Angular 2 Beta、ヒーローズツアーチュートリアルパート2

パート1 パート2 パート3 パート4







もっとヒーローが必要



私たちの物語にはもっと多くのヒーローが必要です。 Heroes Tourアプリケーションを展開して、ユーザーがヒーローを選択し、彼に関する詳細情報を表示できるヒーローのリストを表示します。







アプリケーションを起動する、パート2







ヒーローのリストを表示するために必要なものについて考えてみましょう。 まず、表示するヒーローのリストを含む配列が必要です。 次に、配列からテンプレートにデータを渡す方法が必要です。







私たちが泊まった場所



2番目のヒーローツアーに進む前に、 最初のパートを完了する必要があります。 まだ行っていない場合は、戻ってください。







コード変換とアプリケーション実行をサポート



TypeScriptコンパイラを実行して、ファイルの変更を監視し、すぐにコンパイルし、Webサーバーも起動するようにします。 入力することでこれを行います







npm start
      
      





これにより、ヒーローツアーの作成を継続している間、アプリケーションが実行され続けます。







ヒーローの展示



ヒーロー作成



app.component.ts



の下部に10人のヒーローの配列を作成してみましょう。







app.component.ts(ヒーローの配列)







  let 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" } ];
      
      





HEROES



は、最初のパートで作成したクラスであるHero



タイプの要素の配列です。 もちろん、このヒーローのリストをWebサービスから取得したいのですが、小さなステップを踏んで、最初にモックオブジェクト(以前に指定されたデータを返すスタブ)からヒーローを表示します。







ヒーローの表現



バインドするヒーローのソースとなるプロパティをAppComponent



作成しましょう。







app.component.ts(プロパティ-ヒーローの配列)







  public heroes = HEROES;
      
      





heroes



のタイプを明示的に定義する必要はありません。 TypeScriptはHEROES



変数から取得できます。







ここで、このコンポーネントクラスでヒーローのリストを定義できます。 しかし、最終的にはWebサービスからヒーローを取得することを知っています。 したがって、このデータをクラス実装からすぐに引き出すことは理にかなっています。


テンプレートにヒーローを表示する



コンポーネントにはheroes



が含まれています。 テンプレートに順不同リストを作成して表示してみましょう。 ヒーローに関する詳細情報の上の見出しの下に、次のHTMLを挿入します。







app.component.ts(ヒーローテンプレート)







  <h2>My Heroes</h2> <ul class="heroes"> <li> <!-- each hero goes here --> </li> </ul>
      
      





これで、ヒーローを入力できるテンプレートができました。







ngForでヒーローをリストする



コンポーネント内のヒーローの配列をテンプレートに関連付け、それを反復処理し、各ヒーローを個別に表示したいと思います。 これを行うには、Angularの助けが必要です。 ステップバイステップで始めましょう:

最初に、組み込み*ngFor



ディレクティブを追加して<li>



変更します。







app.component.ts(ngFor)







  <li *ngFor="#hero of heroes">
      
      





* ngFor`の)



の先頭のアスタリスク( ` )



は、構文の重要な部分です。**


ngFor



*



プレフィックスは、 <li>



要素とその子がマスターテンプレートを構成することを示します。







ngFor



ディレクティブはheroes



配列を通過して、 AppComponent.heroes



プロパティを返し、テンプレートに表示します。







ngFor



によって割り当てられた引用テキストは、「 heroes



配列の各ヒーローを取得し、ローカル変数hero



に保存し、対応するテンプレートインスタンスで使用できるようにする」ことを意味します。







hero



前のプレフィックス#



は、ヒーローをローカルテンプレート変数として識別します。 次に、テンプレートでこの変数を参照して、ヒーローのプロパティにアクセスできます。







ngFor



およびローカルテンプレート変数の詳細については、 データマッピングおよびテンプレート構文の章をngFor



ください。







ここで、 <li>



タグの間にコードを挿入します。このコードは、 hero



テンプレート変数を使用してhero



のプロパティを表示します。







app.component.ts(ngForテンプレート)







  <li *ngFor="#hero of heroes"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li>
      
      





ブラウザがページを更新すると、ヒーローのリストが表示されます!







ヒーローにスタイルを追加する



ヒーローのリストはかなり退屈に見えます。 どのヒーローが選択され、カーソルが現在どのヒーローの上にあるかをユーザーが理解できるように、ユーザーに視覚的にわかりやすくしたいと思います。







コンポーネントにスタイルを追加しましょう。 次のCSSクラスを@Component



デコレーターのstyles



プロパティに割り当てます。







app.component.ts(スタイルの追加)







  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; } `]
      
      





長い文字列の複数行表現には、再び `-notationを使用することに注意してください。







コンポーネントにスタイルを割り当てると、スタイルはその特定のコンポーネントのスコープ内にのみ存在します。 したがって、スタイルはAppComponent



のみ適用され、外部HTMLに「漏れる」ことはありません。







ヒーローを表示するためのテンプレートは次のようになります。







app.component.ts(ヒーローのスタイル)







  <h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="#hero of heroes"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul>
      
      





たくさんのスタイル! ここに示すように、それらをコンポーネントの説明に含めるか、別のファイルに移動して、コンポーネントコードを簡素化します。 これは次の章で行います。 とりあえず、そのままにしておきましょう。







ヒーローセレクション



このアプリケーションには、ヒーローのリストと1人のヒーローに関する情報があります。 ヒーローのリストと1人のヒーローは、まったく関係ありません。 ユーザーにリスト内のヒーローを選択してもらい、選択したヒーローに関する情報が詳細ビューに表示されるようにします。 このUIパターンは一般に「マスター/ディテール」として知られています(「マスター/スレーブ」と翻訳されますが、「マスター/ディテール」は将来使用される予定です)。 この場合、マスターはヒーローのリストであり、詳細は選択したヒーローの詳細な表現です。

リスト内のヒーローのクリックのイベントに関連付けられた「selectedHero」コンポーネントのプロパティを介して、マスターを詳細に接続しましょう。







クリックイベント(マウスクリック)



Angularイベントバインディングを使用してクリックイベント処理を挿入することにより、 <li>



変更します。







app.component.ts(クリックイベントキャプチャ)







  <li *ngFor="#hero of heroes" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li>
      
      





イベントバインディングに焦点を当てる:







  (click)="onSelect(hero)"
      
      





括弧は、クリックイベントのターゲットとして<li>



要素を指定します。 等号の右側の式は、 AppComponent



コンポーネントにあるonSelect()



メソッドを呼び出し、 hero



テンプレートのローカル変数を引数として渡します。 これは、以前にngFor



定義したのと同じhero



変数です。







イベントバインディングの詳細については、「 ユーザー入力」および「 テンプレート構文 」の章を参照してください。


クリックハンドラーを追加する



このイベントは、まだ存在しないonSelect



メソッドに関連付けられています。 このメソッドをコンポーネントに追加します。 このメソッドは何をすべきですか? コンポーネントの変数「selected hero」に、ユーザーがクリックしたヒーローを書き込む必要があります。







これまでのところ、コンポーネントにはそのような変数はないので、追加することから始めましょう。







選択したヒーローの任命



AppComponent



hero



プロパティは必要なくなりました。 selectedHero



プロパティに置き換えます。







app.component.ts(selectedHero)







  selectedHero: Hero;
      
      





ユーザーが自分でヒーローを選択するまでヒーローは重要ではないと判断したため、ヒーローで行ったようにselectedHero



初期化しません。







次に、ユーザーがクリックしhero



selectedHero



プロパティに値hero



書き込むonSelect



メソッドを追加します。







app.component.ts(onSelect)







  onSelect(hero: Hero) { this.selectedHero = hero; }
      
      





選択したヒーローの詳細情報をテンプレートに表示する必要があります。 現時点では、テンプレートはまだ古いhero



プロパティにアクセスしています。 テンプレートを修正して、新しいselectedHero



プロパティにバインドします。







app.component.ts(selectedHeroにスナップ)







  <h2>{{selectedHero.name}} details!</h2> <div><label>id: </label>{{selectedHero.id}}</div> <div> <label>name: </label> <input [(ngModel)]="selectedHero.name" placeholder="name"/> </div>
      
      





ngIfで空のデータを非表示にする



アプリケーションをダウンロードすると、ヒーローのリストが表示されますが、ヒーローは選択されていません。 selectedHero



定義さselectedHero



いません。つまり、 undefined



です。 これが、ブラウザコンソールに次のエラーメッセージが表示される理由です。







  EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
      
      





覚えているように、テンプレートにはselectedHero.name



が表示selectedHero.name



れます。 プロパティを含むselectedHero



変数が定義されていないため、 name



プロパティは存在しません。







ヒーローが選択されるまで、ヒーローに関する詳細情報をDOMから削除することにより、この問題を解決します。







ヒーローに関する詳細情報を含むHTMLを<div>



ラップしました。 組み込みの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



変数が値を取得して定義され、 ngIf



がヒーローに関する詳細情報を含むデータをDOMに配置し、ネストされたバインディングを実装します。







ngIf



と `ngFor 'は、「構造ディレクティブ」と呼ばれます。これは、DOMの一部の構造を変更できるためです。 つまり、AngularがDOMでコンテンツをレンダリングする方法の構造を定義します。


ngIf、ngFor、およびその他の構造化ディレクティブの詳細については、 構造ディレクティブテンプレート構文の章を参照してください。







ブラウザが更新され、ヒーローのリストが表示されますが、選択したヒーローに関する詳細情報は表示されません。 NgIf



は、 selectedHero



変数が定義されるまで、DOMの外部に保存します。 リスト内のヒーローをクリックすると、選択したヒーローに関する詳細情報が表示されます。 すべてが期待どおりに機能します。







選択したアイテムのスタイル設定



リストの下に選択したヒーローに関する情報が表示されますが、上のリストではこのヒーローをすばやく見つけることができません。 これを修正するには、CSSでselected



クラスをメインリストの対応する<li>



要素に適用します。 たとえば、ヒーローのリストからマゼンタを選択すると、次のように背景色を変更して視覚的に強調表示することができます。







ヒーローリスト選択







テンプレートでselected



クラスを設定するために、 class



要素にバインディングプロパティを追加します。 これは、現在のselectedHero



hero



を比較する式によって行います。

キーはCSSクラスの名前です( selected



)。 両方のヒーローが一致する場合、値はtrue( true



)、そうでない場合はfalse( false



)です。 「文字が一致する場合はselected



クラスを適用し、一致しない場合は削除します」
と言います







app.component.ts(CSSクラスの設定)







  [class.selected]="hero === selectedHero"
      
      





テンプレートでは、 class.selected



角括弧( []



)で囲まれていることに注意してください。 これは、データソース(式hero === selectedHero



)からclass



プロパティにデータフローが一方向に進むプロパティバインディングの構文です。







app.component.ts(各ヒーローの様式化)







  <li *ngFor="#hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li>
      
      





プロパティのバインドの詳細については、テンプレートの構文の章を参照してください。


ブラウザがアプリケーションを再起動します。 マゼンタのヒーローを選択します。選択は背景色によって明確に識別されます。







ヒーローリスト







別のヒーローを選択すると、背景色がこのヒーローに切り替わります。







現時点でのapp.component.ts



の完全なコンテンツはapp.component.ts



です。







app.component.ts
 import {Component} from 'angular2/core'; export class Hero { id: number; name: string; } @Component({ selector: 'my-app', template:` <h1>{{title}}</h1> <h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="#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) { this.selectedHero = hero; } } var 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" } ];
      
      





歩いた道



この章で達成したことは次のとおりです。









アプリケーションを起動する、パート2







今後のパス



私たちのヒーローツアーは成長しましたが、まだ完全ではありません。 アプリケーション全体を1つのコンポーネントに入れることはできません。 それをサブコンポーネントに分解し、それらを連携させる方法を教える必要があります。 次の章でこれを行う方法を学びます。








All Articles