以反应形式进行双向绑定

时间:2016-11-07 06:02:56

标签: angular angular2-forms angular2-formbuilder

使用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管道中。我怎么能做到这一点?

7 个答案:

答案 0 :(得分:45)

  

注意:,如@Clouse24所述,"Using Reactive Froms with ngModel is deprecated in angular 6 and will be removed in 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指令。

答案 1 :(得分:10)

有时您可能需要将[(ngModel)]与Reactive表单结合使用。我可能是一些你不需要作为表单一部分的输入控件,但你仍然需要将它绑定到控制器。然后您可以使用:[(ngModel)]="something" [ngModelOptions]="{standalone: true}"

答案 2 :(得分:2)

Angular 6+ 解决方案...

我也想要反应式表单验证,同时还使用双向数据绑定。我想出的最佳解决方案是使用 valueChanges 计时器挂钩表单组的 debounce 事件以更新模型。举个例子:

<form [formGroup]="form">
  <input class="form-control" type="date" name="myDate" formControlName="myDate">
</form>
public myModel = {
  myDate: '2021-01-27'
};

public form = this.builder.group({
  myDate: [this.myModel.myDate, [Validators.required]],
});

// Don't update the model with every keypress, instead wait 1s and then update
this.form.valueChanges.pipe(debounceTime(1000)).subscribe((changes) => {
  for (let key of Object.keys(changes)) {
    this.myModel[key] = values[key];
  }
});

为了更好地帮助复制/面食,我将使用给定的更改更新moodle的所有属性的值。如果您只想使用双向数据绑定更新一个属性,您应该使用以下内容:

this.form.get('myDate').valueChanges.pipe(debounceTime(1000)).subscribe((changes) => {
  this.myModel.myDate = changes.myDate;
});

答案 3 :(得分:1)

如果只想显示输入值,只需在输入中创建一个变量并在模板中使用即可。

                         ...很多其他投入         
    <h4>Example values: {{ name.value }}</h4>

答案 4 :(得分:0)

// 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);
}

答案 5 :(得分:0)

这是解决问题的方法:

为了得到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);
}

答案 6 :(得分:0)

可以将

ngModel或模板驱动的形式与反应形式(模型驱动的形式)混合在一起。例如,使用TDF时无需订阅即可轻松读取数据,另一方面,您可以使用MDF提供一些验证。但我只希望选择其中之一。

TDF的最大缺点是您不能对其进行单元测试,另一方面,使用TDF时模板更脏。