使用 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 管道中。我怎样才能做到这一点?
注意:正如@Clouse24 所提到的,“Angular 6 中不推荐使用带有 ngModel 的 Reactive Froms,并将在 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
指令。
有时您可能需要将 [(ngModel)] 与响应式表单结合使用。我可能是一些你不需要的输入控件作为表单的一部分,但你仍然需要将它绑定到控制器。然后您可以使用:[(ngModel)]="something" [ngModelOptions]="{standalone: true}"
It looks like you're using ngModel on the same form field as formControlName. Support for using the ngModel input property and ngModelChange event with reactive form directives has been deprecated in Angular v6 and will be removed in a future version of Angular.
以下是您可以解决的方法:
快捷方式 --> STACKBLITZ
为了得到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);
}
formGroup = new FormGroup({ name: new FormControl(['Michelangelo', {modelBinding: true}]) })
所以我们实际上可以将它绑定到模型而不是手动更新它。
// 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);
}
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;
});
ngModel
。我阅读了弃用文档,其中说这是因为它令人困惑。但这对我来说似乎更方便。
如果您只想显示输入值,只需在输入中创建一个变量并在模板中使用。
<form [formGroup]="form">
<input type="text" formControlName="name" #name>
... lots of other inputs
</form>
<h4>Example values: {{ name.value }}</h4>
ngModel 或模板驱动表单和响应式表单(模型驱动表单)可以混合在一起。例如,当您使用 TDF 时,无需订阅即可轻松读取数据,另一方面,您可以使用 MDF 提供一些验证。但我宁愿只选择其中之一。
TDF 的最大缺点是您不能对它们应用单元测试,另一方面,当您使用 TDF 时模板更加脏。
您可以使用反应式表单实现两种方式绑定
constructor(private fb: FormBuilder) this.formData= fb.group({ variable: new FormControl(value,Validators.required) }) //'value'属性携带你要绑定的值 var value="Eamanpreet Singh"