Angularのデータバインディングとは?バインディングの種類と更新の方法。

Angularのデータバインディングとは?バインディングの種類と更新の方法。

この記事では、Angularでもっとも重要な機能ともいえるデータバインディングについてその種類や使い方を説明していきたい。

Angularにはデータとビューを結びつけるための様々な機能が存在する。それらはAngularの強みでもある反面、様々な記述方法が混在するため初学者にとっては覚えるのが大変だったりもする。

Angularでアプリを制作するならばまず最初に理解しておきたい部分なので、頑張って見ていこう!

データバインディングとは?

まずはバインディング(データバインディング)とはどんな機能なのか確認したい。

バインディングはコンポーネントのデータとビューを紐づけるための仕組みでAngularの最大の特徴だ。

バインディングされた変数に変更があった場合は紐づけられた値が自動で更新される。

以下の図はAngularのデータバインディングの概要を表している。

Angularのデータバインディング

片方向バインディングと双方向バインディング

Angularのバインディングには片方向バインディングと双方向バインディングがある。

片方向バインディングでは、値の変更やイベントはテンプレート・コンポーネントのいずれかからもう片方へと伝えられる。

双方向バインディングにおいては、値の変更は双方向に伝えられ、紐づけられた値はシンクロした状態となる。

Angularのバインディングの種類

Angularのバインディングには大きく分けて以下の4種類が存在する。

  • Interpolation(補間)
  • プロパティ(属性)バインディング
  • イベントバインディング
  • 双方向バインディング

次の章からはそれぞれを詳しく説明していく。

AngularとAngularJSの構文
Angularの前身にあたるAngularJS。AngularJSとAngularの違いはとても大きく別のフレームワークと考えたほうが理解しやすいだろう。特にデータバインディングの構文においては両者の違いが謙虚。StackOverflowなどでAngularのサンプルコードを探す場合は見つけたコードがAngularのものであるかどうかをまず確認するようにしよう!

Interpolation(補間)

Interpolationはバインディングの中でももっとも基本的な構文。

HTMLに変数に納められた値や計算式、またメソッドの結果を出力するために使われる。

試しにコンポーネントに文字や数値を代入した変数を作成してHTMLで表示してみよう。

myText = 'こんにちは';
{{ myText }}

Interpolationは数式や関数を使用することもできる。

{{ 3 * 5 }}
{{ getText() }}

またパイプを使用さればDateオブジェクトやJSONデータも出力することができる。

{{ today | date: 'medium' }}

パイプについて詳しく知りたい人はこちらの記事を参考にしてほしい。

バインディングされた値の更新

バインディングは変数などの値が更新されるたびに通常自動でアップデートされる。

以下のコードを書いて、値の変更がビューに反映されるのを確認してみよう。

export class AppComponent {

  public value: number = 0;

  constructor(private _ch: ChangeDetectorRef) {
    interval(1000).pipe(take(10)).pipe(map(number =>
      number++
    )).subscribe(count => {
      this.value = count
    });
  }
}

正常であれば表示される数が1秒ごとに更新されるはずだ。

なお、Angularの設定によっては値の変更をビューに知らせてあげる必要がある場合もある。

その場合は、ChangeDetectorRefのdetectChanges関数などを使用して変更を知らせる。

プロパティ(要素)バインディング

プロパティ(要素)バインディングはInterpolationと並んでよく使われるデータバインディングの種類だ。

プロパティバインディングでは、「input」「table」といったHTML要素のプロパティと変数などの値が紐づけられる。

プロパティバインディングには以下の3種類が存在する。

  • 属性バインディング
  • クラスバインディング
  • スタイルバインディング

それぞれを詳しく見ていこう。

属性バインディング

属性バインディングではHTML要素が持つ属性をコントロールする。

ここでいう「属性」とは、<form>要素の「action」や<col>要素の「span」などのことで、「offsetWidth」などスタイリングにまつわるものはスタイルバインディングの項で紹介する。

ここでは<option>要素の「selected」属性を例にして使い方を紹介したい。

public favAnimal = 'cat';
<select>
  <option [selected]="favAnimal === 'dog'" value="dog">Dog</option>
  <option [selected]="favAnimal === 'cat'" value="cat">Cat</option>
  <option value="hamster">Hamster</option>
  <option value="parrot">Parrot</option>
</select>

「selected」はドロップダウンで予め選択されているアイテムを指定するための属性。

favAnimalの値を変更することでデフォルトで選択されているアイテムを変えることができる。

クラスバインディング

クラスバインディングは要素にセットされているクラスを変更するためのバインディングであり、便利で使用頻度も高い。

ここでは例としてボタンのクリックでクラスのオンオフを切り替えるパターンを紹介する。

まずはCSS上に新しいクラスを作成する。

.emphasized {
  color: red;
  font-weight: bold;
}

スイッチの役割を果たすbooleanをコンポーネントに作成する。

 public isNew = false;

ボタンのクリックでisNewの値が切り替わるようにHTMLを記述する。

以下の例では[class.emphasized]でクラスのバインディングをおこなっている。

<label [class.emphasized]="isNew">ニュース</label>
<button (click)="isNew = !isNew">チェンジ</button>

なお、label要素はクラスディレクティブと呼ばれる[ngClass]を使用して記述することもできる。

<label class="text" [ngClass]="isNew ? 'emphasized' : ''">ニュース</label>

スタイルバインディング

CSSのプロパティをひとつだけ変更したい場合はスタイルバインディングを使うといい。

クラスバインディングがクラスの追加や変更をこなったのに対し、スタイルバインディングは要素のひとつのプロパティと結びつく。

public textSize = '30px';
<label [style.font-size]="textSize">注目!!</label>

またこのコードはスタイルディレクティブと呼ばれる「ngStyle」を使い以下のように書き換えることもできる。

<label [ngStyle]="{'font-size': textSize}">注目!!</label>

イベントバインディング

イベントバインディングはボタンのクリックや文字の入力などといったイベントをトリガーとしたバインディングだ。

Interpolationやプロパティバインディングと異なり、テンプレートからコンポーネントに向けて情報が引き渡される。

イベントバインディングは以下のように記述する。

<button (click)="updateValue()"></button>

イベント名は丸カッコで囲み、呼び起こす処理を記述する。

セミコロンで区切れば複数の処理を記述することもできる。

(click)="updateValue(); element.hidden=false"

また、$eventと記述すればイベントオブジェクトを引数として渡すことができる。

(click)="updateValue($event)"

イベントの種類

トリガーとなるイベントにはおもに以下のような種類がある。

イベント説明
click要素のクリック時に発生
mousedownマウスのボタンを押した際に発生
focus要素がフォーカスされた際に発生
blur要素からフォーカスが外れた際に発生
keypressキーを入力した際に発生
input入力内容の変更時に発生
selectアイテムが選択された時に発生
submit実行(サブミット)時に発生
resetリセット時に発生

「keydown」「keypress」「keyup」のように類似するが、発生するタイミングの異なるイベントも存在する。

思わぬタイミングでメソッドが実行され予期せぬ結果が起きないようにイベントの違いを理解しておくといい。

双方向バインディング

最後にAngularの最大の武器である双方向バインディングについて見てみたい。

双方向はバインディングはコンポーネントとビューの双方が情報を反映しあうバインディングで、コンポーネントの変更はビューへ、ビューへの変更はコンポーネントへと伝えられる。

双方向バインディングは特にHTMLのinputでよく使用される。

例としてinput要素にて双方向バインディングを使用してみよう。

public DEFAULT_EMAIL = 'abc@dfg.co.jp';
public email: string = this.DEFAULT_EMAIL;

printEmail() {
  console.log('email -> ' + this.email);
}

resetEmail() {
  this.email = this.DEFAULT_EMAIL;
}

双方向バインディングは[(ngModel)]で示す。

<input type="email" [(ngModel)]="email" />
<button (click)="printEmail()">出力</button>
<button (click)="resetEmail()">リセット</button>

インプットフィールドに文字を入力して出力ボタンをクリックするとビューでの変更がコンポーネントへと伝わっていることが分かる。

また、リセットボタンをクリックするとemailがリセットされるとともに、その変更がビューにも伝わっていることが分かる。

バインディングの記述ルール
気づいた人もいるかもしれないが、バインディングの種類はカッコの形によって表されている。
  • [ ] ⇐ コンポーネントからビューへのバインディング
  • ( ) ⇐ ビューからコンポーネントへのバインディング
  • [( )] ⇐ 双方向のバインディング