反应形式的两种方式绑定

Two way binding in reactive forms

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

Note: as mentioned by @Clouse24, "Using Reactive Froms with ngModel is deprecated in angular 6 and will be removed in a future version of Angular" (which means that the answer below will no longer be supported in the future). Please read the link to see the reasoning for deprecation and to see what alternatives you will have.

您可以将 [(ngModel)] 与 Reactive 表单一起使用。

模板

<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 指令。

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

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

<form [formGroup]="form">
  <input type="text" formControlName="name" #name>
  ... lots of other inputs
</form>

<h4>Example values: {{ name.value }}</h4>
    // 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);
    }

解决方法如下:

为了得到two-way-binding

的结果

我使用本地 "template variables" 并对两个字段使用相同的 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);
}

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

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

一个 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];
  }
});

为了更好地帮助 copy/pasta 我将使用给定的更改更新 moodel 的所有属性的值。如果你只想用双向数据绑定更新一个 属性 你应该使用像这样的东西:

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

您可以使用 Reactive 表单实现双向绑定

constructor(private fb: FormBuilder)

this.formData= fb.group({
        variable: new FormControl(value,Validators.required)
      })
      
      //the 'value' attribute carries the value you want to bind
var value="Eamanpreet Singh"

<form [formGroup]="formData" (ngSubmit)="submit();">
      <mat-form-field>
            <input matInput placeholder="Name" formControlName="variable">
      </mat-form-field>