79

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

4

8 回答 8

72

注意:正如@Clouse24所提到的,“Angular 6 中不推荐将 Reactive Froms 与 ngModel 一起使用,并将在 Angular 的未来版本中删除”(这意味着未来将不再支持以下答案)。请阅读链接以查看弃用的原因并查看您将拥有哪些替代方案。

您可以使用[(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: ""
    });
  }
}

普朗克

这将是一个完全不同的指令,与没有formControlName. 对于反应形式,它将是FormControlNameDirective. 如果没有,将使用formControlName该指令。NgModel

于 2016-11-07T06:49:41.013 回答
18

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

于 2017-10-20T07:32:30.773 回答
16

以下是您可以解决的方法:

为了得到结果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);
}
于 2019-06-19T12:35:27.397 回答
4
    // 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);
    }
于 2019-05-15T15:37:32.583 回答
3

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

为了更好地帮助复制/意大利面,我将使用给定的更改更新穆德尔所有属性的值。如果你只想用双向数据绑定更新一个属性,你应该使用类似的东西:

this.form.get('myDate').valueChanges.pipe(debounceTime(1000)).subscribe((changes) => {
  this.myModel.myDate = changes.myDate;
});
于 2021-01-28T03:26:38.243 回答
2

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

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

<h4>Example values: {{ name.value }}</h4>
于 2018-09-10T20:39:17.787 回答
0

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

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

于 2019-11-25T16:24:39.773 回答
0

您可以使用反应式表单实现两种方式绑定

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>

于 2021-08-27T05:59:37.707 回答