CodeZine(コードジン)

特集ページ一覧

「Angular 2」の構成単位「コンポーネント」「モジュール」を使いこなそう

次世代Webアプリケーションフレームワーク「Angular」の活用 第3回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
目次

複数コンポーネントを利用するサンプル

 コンポーネントとモジュールの記述方法を、サンプルコードで説明します。今回はWebページに複数のコンポーネントを追加して、コンポーネント間でデータの送受信をするところまでを説明します。これらのコンポーネントをモジュールに切り出す方法は次回記事で取り上げます。

 もとにするサンプル(angular2-001-component1)は、コンポーネント内に定義されたスマートフォン情報配列の内容を、ngForディレクティブで繰り返し表示します。詳細はダウンロードできるサンプルコードを参照してください。

図3 angular2-001-component1サンプルの実行結果
図3 angular2-001-component1サンプルの実行結果

コンポーネント1:詳細表示コンポーネント

 まず、別コンポーネントに値を渡す例として、リストのリンクをクリックして選択したスマートフォンの詳細を図4のように表示するコンポーネント(赤背景の部分)を追加します。

図4 詳細表示コンポーネントの表示(angular2-002-component2)
図4 詳細表示コンポーネントの表示(angular2-002-component2)

 ルートコンポーネント(AppComponent)のテンプレートをリスト4のように編集します。

リスト4 詳細表示のためのテンプレート(angular2-002-component2/app/app.component.ts)
<ul>
  <li *ngFor="let phone of phones">
    <!-- 一覧表示にリンクを設定 ...(1) -->
    <a href="#" (click)="onClick(phone)">{{phone.name}} ({{phone.vendor}})</a>
  </li>
</ul>

<!-- 詳細表示 ...(2) -->
<phone-detail [phone]="selectedPhone"></phone-detail>

 (1)が一覧表示部です。ngForディレクティブで繰り返し表示される部分にリンクを設定して、クリック時にonClickイベントハンドラを実行するようにします。(2)はこれから作る詳細表示コンポーネントを表示する部分で、「[phone]="selectedPhone"」は、phone属性経由で変数selectedPhoneを詳細表示コンポーネントに渡すことを表します。

 リンククリック時の処理onClickはリスト5のようになります。選択されたスマートフォンに対応するオブジェクトphoneを、コンポーネントの変数selectedPhoneに格納します。

リスト5 リンククリック時のハンドラ(angular2-002-component2/app/app.component.ts)
onClick(phone: Phone) {
  this.selectedPhone = phone;
}

 次に、リスト4(2)のphone-detail要素に表示される詳細表示コンポーネントをリスト6のように定義します。

リスト6 詳細表示コンポーネント(angular2-002-component2/app/phonedetail.component.ts)
// Angular 2のコンポーネント参照 ...(1)
import { Component, Input } from "@angular/core";
// Phoneクラスの参照 ...(2)
import { Phone } from "./phone";

// コンポーネントのメタデータ定義 ...(3)
@Component({
  selector: "phone-detail",
  styles: ["div.component { background:#ffd5d5}"],
  template: `
  <div class="component" *ngIf="phone">
    <h4>【PhoneDetailComponent: 詳細表示】</h4>
    <ul>
      <li>名前: {{phone.name}}</li>
      <li>会社: {{phone.vendor}}</li>
      <li>発売: {{phone.delivery}}</li>
    </ul>
  `
})

// コンポーネントクラス定義 ...(4)
export class PhoneDetailComponent {
  // phone-detailディレクティブの「phone」属性でPhoneオブジェクトを指定する記述
  @Input("phone") phone: Phone;
}

 (1)はAngular 2のコンポーネント参照、(2)はスマートフォン情報を格納するPhoneクラス定義の参照です。(3)のメタデータ定義で、selector属性にHTMLタグ名(phone-detail)、template属性にテンプレートを、それぞれ設定しています。styles属性は必須ではありませんが、ここではコンポーネントの表示範囲がわかりやすいように背景色を設定しています。

 (4)はコンポーネントクラスの定義です。(1)で参照した@Inputデコレーターを変数phoneの前に「@Input("phone")」のように記述すると、タグのphone属性に指定されたオブジェクトが取得できます。コンポーネント間で値を引き渡すという意味で、AngularJS 1のbindControllerと似た機能といえます。なお、属性名と変数名が同じ場合はリスト7のような省略記法が利用できます。

リスト7 @Inputの省略記法
@Input() phone: Phone;
// 「@Input("phone") phone: Phone」と同じ意味

 ルートコンポーネント側のリスト4(2)との組み合わせで、ルートコンポーネントで選択されたスマートフォン情報(selectedPhone)が、詳細表示コンポーネントの変数phoneに設定されます。設定されたphoneの内容は{{}}記述によるデータバインディングで画面に反映されます。

 リスト4~6を実行してスマートフォンのリンクをクリックすると、phone-detail要素の場所に図4のように詳細表示コンポーネントが表示されます。

コンポーネント2:項目追加コンポーネント

 次に、別コンポーネントから値を受け取る例として、スマートフォンの項目を新しくリストに追加する図5コンポーネント(青背景の部分)を定義していきます。

図5 項目追加コンポーネントの表示(angular2-003-component3)
図5 項目追加コンポーネントの表示(angular2-003-component3)

 AppComponentのテンプレートに、項目追加コンポーネントの表示指定をリスト8のように追加します。

リスト8 項目追加コンポーネントの表示指定(angular2-003-component3/app/app.component.ts)
<!-- 新規入力 -->
<phone-input (onSubmitted)="onSubmittedPhoneInput($event)"></phone-input>

 リスト8のonSubmittedは、入力値が登録されたときに発生するイベントで、後述する詳細表示コンポーネントで定義します。詳細表示から渡されるイベント変数は$eventで参照されるので、それを引数にしてイベントハンドラ(onSubmittedPhoneInputメソッド)を実行します。

 onSubmittedPhoneInputメソッドの実装はリスト9です。イベント引数として渡されるphoneオブジェクトを、自身が持つ配列phonesの末尾に追加します。

リスト9 項目追加コンポーネントからのイベント処理(angular2-003-component3/app/app.component.ts)
onSubmittedPhoneInput(phone: Phone) {
  this.phones.push(phone);
}

 次に項目追加コンポーネントをリスト10のように記述します。

リスト10 項目追加コンポーネント(angular2-003-component3/app/phoneinput.component.ts)
// コンポーネント、クラスの参照 ...(1)
import { Component, EventEmitter, Output } from "@angular/core";
import { Phone } from "./phone";

// コンポーネントのメタデータ定義 ...(2)
@Component({
  selector: "phone-input",
  styles: ["div.component { background:#d7e3f4}"],
  template: `
  <div class="component">
    <h4>【PhoneInputComponent: 項目追加】</h4>
    <input type="text" placeholder="名前" [(ngModel)]="newPhone.name"><br/>
    <input type="text" placeholder="会社" [(ngModel)]="newPhone.vendor"><br/>
    <input type="text" placeholder="発売" [(ngModel)]="newPhone.delivery"><br/>
    <button (click)="onClick();">追加</button>
  </div>
  `
})

// コンポーネントクラス定義
export class PhoneInputComponent {
  // 追加するPhoneオブジェクト ...(3)
  newPhone:Phone = new Phone();

  // 追加時に発生させるイベント ...(4)
  @Output("onSubmitted") onSubmitted = new EventEmitter<Phone>();

  /**
   * 追加ボタンクリック時のハンドラ ...(5)
   */
  onClick() {
    // newPhoneを引数にしてonSubmittedイベント発生
    this.onSubmitted.emit(this.newPhone);
    // newPhoneオブジェクトを再生成してフォームリセット ...(6)
    this.newPhone = new Phone();
  }
}

 (1)はAngular 2コンポーネントとPhoneクラスの参照、(2)が項目追加コンポーネントのメタデータ定義です。フォームの入力内容を[(ngModel)]による双方向データバインディングでコンポーネントクラスの変数newPhone(3)と同期するようになっています。

 (1)で参照したEventEmitterと@Outputデコレーターを用いて、(4)でルートコンポーネントへ伝達するイベントを定義しています。@Output("onSubmitted")は、ルートコンポーネントでonSubmittedイベントを発生させる意味です。また、EventEmitterで指定している<Phone>記述は、イベントに引き渡すパラメータ変数がPhoneクラスであることを表しています。なお、発生させるイベント名と変数名が同じ場合はリスト11のような省略記法が利用できます。

リスト11 @Outputの省略記法
@Output() onSubmitted = new EventEmitter<Phone>();
//「@Output("onSubmitted") onSubmitted」と等価

 (6)は、newPhoneに新しい(空の)Phoneオブジェクトを設定して、入力フォームの内容をリセットするための処理です。

 テンプレートの確定ボタンがクリックされると、(5)のonClickメソッド内でonSubmited.emitメソッドが実行され、引数にnewPhoneを指定したonSubmittedイベントを発生させます。ルートコンポーネントでは、リスト8、9の実装でイベント引数からnewPhoneの情報を取り出してスマートフォンリストに追加します。

 リスト8~10を実行すると、図5のように項目追加コンポーネントが表示され、入力した内容がスマートフォンリストに追加されます。

まとめ

 本記事では、Angular 2でプログラムを分割するコンポーネントやモジュールについて説明し、コンポーネントの実装方法をサンプルで説明しました。コンポーネントやモジュールにより、影響範囲が局所化された効率的なコードを記述でき、共通の機能をモジュールにして部品化するなど、生産効率の向上が期待できます。

 モジュールには今回説明したコンポーネントのほかに、共通処理などを提供する「サービス」と呼ばれる要素を含めることができます。次回は今回作成したコンポーネントをモジュールに切り出す方法を解説するとともに、サービスとそれを利用するためのDependency injection(依存性の注入)について説明します。

参考資料



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:次世代Webアプリケーションフレームワーク「Angular」の活用

もっと読む

著者プロフィール

  • WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5