この記事ではngModelを利用せずに、カスタムコンポーネントで双方向バインディングを実現する方法を解説します。
Angularではbanana in a box syntaxを用いることで、双方向バインディングを簡単に実装することが可能です。
目次
banana in a box syntaxとは
banana in a box syntaxとは[(ngModel)]を利用する際に見かける記法、[()]の事を指します。
[]=> box()=> banana[()]=> banana in a box
という事です。
[()]記法は、Angularが備えているテンプレート構文の一種で、プロパティバインディングとイベントバインディングを組み合わせたものと同様の振る舞いをします。
[()]を用いた場合:
<my-component [(value)]="text"></my-component>
プロパティバインディングとイベントバインディングに分解した場合:
<my-component [value]="text" (valueChange)="text=$event"></my-component>
カスタムコンポーネントの実装例
ここでは要素がクリックされた際に[()]へ指定された変数が更新されるカスタムコンポーネントを考えます。
まずカスタムコンポーネントを実装します。
@Component({
selector: 'my-component',
template: `<div (click)="onClick()">Hello My Component!</div>`
})
export class MyComponent
{
@Input()
public value: string = '';
@Output()
public valueChange = new EventEmitter<string>();
public onClick(): void
{
this.value = 'Component clicked!';
this.valueChange.emit(this.value);
}
}
上記で実装したカスタムコンポーネントを、利用したいコンポーネントから呼び出します。
@Component({
selector: 'parent-component',
template: `
<my-component [(value)]="text"></my-component>
<pre>{{text}}</pre>
`
})
export class ParentComponent
{
public text: string = '';
}
この状態でparent-componentを呼び出した場合、画面上へはHello My Component!が表示されます。
そしてHello My Component!をクリックすると、parent-componentのメンバ変数textにComponent clicked!がセットされ画面上に表示されます。
解説
- カスタムコンポーネントは
@Input() public value: string = '';にてvalueを受け取ります。 - カスタムコンポーネントは
valueが更新された際、それを親へ伝達するためthis.valueChange.emit(this.value);を呼び出します。
[(value)]記法を用いる場合、カスタムコンポーネント側の@Input()プロパティ名にChangeサフィックスを追加した変数名を、@Outputプロパティとして設定すれば良いわけです。