web-dev-qa-db-ja.com

リアクティブ形式の双方向バインディング

Angular 2を使用すると、テンプレートドリブンフォームで双方向バインディングが簡単になります。バナナボックス構文を使用するだけです。この動作をモデル駆動型のフォームでどのように再現しますか?

たとえば、標準的なリアクティブフォームは次のとおりです。見た目よりもはるかに複雑で、多くのさまざまな入力とビジネスロジックがあるため、テンプレート駆動型アプローチよりもモデル駆動型アプローチの方が適切であるとします。

export class ExampleModel {
    public name: string;
    // ... lots of other inputs
}

@Component({
    template: `
        <form [formGroup]="form">
            <input type="text" formControlName="name">
            ... lots of other inputs
        </form>

        <h4>Example values: {{example | json}}</h4>
    `
})
export class ExampleComponent {
    public form: FormGroup;
    public example: ExampleModel = new ExampleModel();

    constructor(private _fb: FormBuilder) {
        this.form = this._fb.group({
            name: [ this.example.name, Validators.required ]
            // lots of other inputs
        });
    }

    this.form.valueChanges.subscribe({
        form => {
            console.info('form values', form);
        }
    });
}

subscribe()では、あらゆる種類のロジックをフォーム値に適用し、必要に応じてマップできます。ただし、フォームのすべての入力値をマップする必要はありません。 employeeモデル全体の値を、[(ngModel)]="example.name"と同様のアプローチで更新し、テンプレートのjsonパイプに表示されるように表示したいだけです。どうすればこれを達成できますか?

44
ebakunin

注: @ Clouse24 "ngModelでのReactive Fromsの使用で言及されているように angular 6では非推奨であり、angular 7 " で削除されます(つまり、バージョン7以降では以下の回答はサポートされなくなります)。リンクを読んで、サポート終了の理由を確認し、代替案を確認してください。

[(ngModel)]をリアクティブフォームで使用できます。

<form [formGroup]="form">
  <input name="first" formControlName="first" [(ngModel)]="example.first"/>
  <input name="last" formControlName="last" [(ngModel)]="example.last"/>
</form>

export class App {
  form: FormGroup;
  example = { first: '', last: '' };

  constructor(builder: FormBuilder) {
    this.form = builder.group({
      first: '',
      last: ''
    })
  }
}

Plunker

これは、formControlNameなしで使用されるディレクティブとは完全に異なるディレクティブになります。リアクティブフォームでは、FormControlNameDirectiveになります。 formControlNameがない場合、NgModelディレクティブが使用されます。

51
Paul Samsotha

[(ngModel)]とリアクティブフォームを組み合わせる必要がある場合があります。フォームの一部としては必要ない入力コントロールの場合もありますが、それでもコントローラーにバインドする必要があります。次に、使用できます:[(ngModel)]="something" [ngModelOptions]="{standalone: true}"

10
Jens Alenius

解決方法は次のとおりです。

two-way-bindingの結果を得るために

ローカルの「テンプレート変数」を使用し、両方のフィールドに同じformControlを使用します。

<form [formGroup]="formGroup">
  <input #myInput (input)="mySlider.value = myInput.value" type="number" formControlName="twoWayControl">

  <mat-slider #mySlider (input)="myInput.value = mySlider.value" formControlName="twoWayControl" min="1" max="100">
  </mat-slider>

</form>

プログラムでモデルの値を変更したい場合、他の人が宣言しているように、setValue()を使用します。

setTo33() {
  this.formGroup.get('twoWayControl').setValue(33);
}
2
Andre Elrico

入力値を表示するだけの場合は、入力に変数を作成し、テンプレートで使用します。

    <h4>Example values: {{ name.value }}</h4>
1
Matheus Bueno
// Allow two way binding on the [(name)] from the parent component
private nameValue: string;
@Input()
get name() {
    return this.nameValue;
}
set name(values) {
    this.nameValue = values;
    this.nameChange.emit(this.nameValue);
}
@Output() nameChange = new EventEmitter<string>();

ngOnInit() {
    // Update local value and notify parent on control value change
    this.formControl.valueChanges.forEach(value => this.name = value));
}

ngOnChanges() {
    // Update local value on parent change
    this.formControl.setValue(this.expression);
}
0
Vedran