Angularで「フォーム」の入力値をコンポーネントと同期するには?(双方向バインディング)Angular TIPS

テンプレート上のフォーム入力値とコンポーネントのプロパティ値を双方向にバインドするTwo-way Bindingのバインディング構文を説明し、その仕組みを紹介する。

» 2017年07月14日 05時00分 公開
[山田祥寛]
「Angular TIPS」のインデックス

連載目次

現在では、Web標準技術を利用したアプリ開発が広く普及し、そのためのフレームワークも多数存在しています。その中でも主流のフレームワークの1つである「Angular」を活用し、そのための知識を備えることには大きな意味があります。本連載は、Angularユーザーに向けて、その使いこなしTIPSを紹介するものです。なお、本連載は「Build Insider」で公開していた連載「Angular Tips」を同サイトおよび筆者の了解を得たうえで、本フォーラムに移行したものです。記事はBuild Insiderで公開した状態のまま移行しているため、用語統一などの基準が@ITの通常の記事とは異なる場合があります。


【対応バージョン】

 Angular 4以降。v4時点で執筆しました。


 {{...}}式Property BindingAttribute BindingEvent Bindingなど、ここまでに解説してきたバインド構文は、いずれもコンポーネント→テンプレート方向、もしくはテンプレート→コンポーネント方向の、いわゆる片方向バインディングを表すものでした。

 一方、コンポーネントの値とテンプレート上の値とを双方向に同期させるためのバインド構文を双方向バインディングと言います。コンポーネントの値(プロパティ)が変化したらテンプレートにも反映し、テンプレートの値を変えたら(例えばテキストボックスに値が入力されたら)コンポーネントのプロパティにも書き戻す、そんなバインド構文です。

 具体的な例も見てみましょう。以下は、テキストボックスに入力した値に基づいて、「Hello, ●○!!」というメッセージを表示する例です。テキストボックスにはデフォルト値として「Tom」をセットするものとします。

テキストボックスの値に応じて、挨拶メッセージを表示

テキストボックスに「山田太郎」と入力し直すと……

テキストボックスの値に応じて、挨拶メッセージを表示 テキストボックスの値に応じて、挨拶メッセージを表示

【1】FormsModuleモジュールをインポートする

 Angularのフォーム機能を利用するために、FormsModuleをインポートしておきます*1。別モジュールをインポートするには、@NgModuleデコレーターのimportsパラメーターを利用します。

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';

import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

FormsModuleモジュールをインポートするコード(app.module.ts)

*1 Angularのフォーム機能については、後日別稿「TIPS:入力フォームに検証機能を実装するには?(form/input)」で解説する予定です。


【2】コンポーネントを準備する

 あとは、テキストボックスを備えたコンポーネントを作成するだけです。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <form>
      <label for="name">名前:</label>
      <!--[1]テキストボックスtxtNameに対してnameプロパティをひも付け-->
      <input id="txtName" name="txtName" type="text"
        [(ngModel)]="name" />
      <!--[2]nameプロパティをもとに挨拶メッセージを生成-->
      <div>Hello, {{name}}!!</div>
    </form>
  `,
})
export class AppComponent  {
  // [3]デフォルト値を設定
  name = 'Tom';
}

双方向バインディングの基本的な例(app.component.ts)
各番号に対する説明は後の本文に記載しています。

 <input>/<select>などの入力要素を、コンポーネントのプロパティと同期させるには、ngModelディレクティブを利用します。ngModelを利用する際は、入力要素をコンポーネント側から識別できるように、name属性は必須です。

[構文]ngModelディレクティブ(双方向バインディング)

[(ngModel)]="prop"

  • prop: コンポーネントのプロパティ

 双方向バインディングでは、ngModelディレクティブを[(...)]でくくります。[...]はProperty Binding(コンポーネント→テンプレート)を、(...)はEvent Binding(テンプレート→コンポーネント)を表しますので、両者を組み合わせたのが[(...)](双方向バインディング)というわけです。

 [1]のように表すことで、テキストボックスtxtNameがコンポーネントのnameプロパティに同期します。つまり、nameプロパティ([3])の初期値がそのままテキストボックスの初期値として反映されますし、テキストボックスを更新すると、プロパティ値にも反映され、結果として[2]のメッセージにも反映されます。

補足:双方向バインディングの仕組み

 双方向バインディングの仕組みを理解するために、[1]のコードを双方向バインディングを利用せずに表してみましょう。

<input id="txtName" name="txtName" type="text"
  [ngModel]="name"
  (input)="name=$event.target.value" />

[(...)]構文を利用せずに双方向バインディングを実装したコード(app.component.ts)

 まず、[ngModel]="name"でnameプロパティの値をngModelディレクティブにバインドします。Property Binding構文です。

 「(input)="name=$event.target.value"」はEvent Bindingの構文で、inputイベント(=入力値が変更された)のタイミングで、ターゲット要素($event.target*2)の値(value)をnameプロパティに代入します。

 このように、双方向バインディング([(...)])とは、内部的には、Property BindingとEvent Bindingの組み合わせによって表現できます。

*2 $eventはイベント情報を管理するためのイベントオブジェクトです。詳しくは、後日別稿「TIPS:イベントハンドラーでイベント情報を参照するには?($event)」で解説する予定です。


処理対象:テンプレート構文(Template Syntax) カテゴリ:基本
処理対象:双方向バインディング(Two-way Binding) カテゴリ:テンプレート構文(Template Syntax)
処理対象:バインディング構文(Binding Syntax) カテゴリ:テンプレート構文(Template Syntax)
処理対象:[(ngModel)]="プロパティ名" カテゴリ:テンプレート構文(Template Syntax) > バインディング構文(Binding Syntax)
API:NgModel カテゴリ:@angular > forms > DIRECTIVE(ディレクティブ)
API:FormsModule カテゴリ:@angular > forms > CLASS(クラス)
API:@NgModuleデコレーター カテゴリ:ADVANCED > Angular Modules


「Angular TIPS」のインデックス

Angular TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。