概要
今回はControlValueAccessor
を使用した双方向バインディングの実装の仕方を記載します。
通常の双方向バインディングの実装については以下の記事を参照して下さい。 kakkoyakakko2.hatenablog.com
動作環境
- TypeScript 2.9.x
- Angular 6.1.x
ControlValueAccessorの利点
input
系のFormControl
のように使用できる[(ngModel)]
でバインディング- Validatorに対応
実装方法
下記のような設定をします。
- 自作コンポーネント
- ControlValueAccessorインターフェースを実装する。
NG_VALUE_ACCESSOR
をprovideする。
- 呼び出し側コンポーネント
[(ngModel)]="呼び出し側プロパティ"
のように呼び出す。
- NgModule
FormsModule
をimportする。
サンプルソース
custom-list.component.ts
import { Component, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'custom-list', template: ` <ul> <li *ngFor="let num of list" (click)="changeValue(num)" [style.background-color]="num === value ? 'yellow' : 'white'"> {{ num }} </li> </ul> `, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CustomListComponent), multi: true } ] }) export class CustomListComponent implements ControlValueAccessor { /** 選択値 */ value: number = 0; /** 表示リスト */ list: number[] = [1, 2, 3, 4, 5]; private fnChange = (_: any) => {}; private fnTouched = () => {}; writeValue(value: any): void { this.value = value ? value : 0; } registerOnChange(fn: any): void { this.fnChange = fn; } registerOnTouched(fn: any): void { this.fnTouched = fn; } setDisabledState(isDisabled: boolean): void { } /** * 選択値変更処理 * @param num */ changeValue(num: number): void { this.value = num; this.fnChange(num); } }
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <h2>TwoWay Binding Sample(ControlValueAccessor)</h2> <custom-list [(ngModel)]="num"></custom-list> <div>num: {{ num }}</div> ` }) export class AppComponent { num: number = 2; }
実行結果