Angular 表单变化检测
Angular form change detection
我正在使用 Angular 表单,我想使用它们内置的更改检测来实现我的应用程序中的功能。当用户单击按钮时,如果 he/she 对表单进行了任何更改,他应该只会看到一个对话框。
我更改了变量:
private changesMade: boolean;
这是我的形式的 TS 代码:
this.carForm = new FormGroup({
name: new FormControl('', [
Validators.required,
Validators.pattern('[a-zA-Z ]*'),
Validators.minLength(1),
Validators.maxLength(10)
])});
这是我的 HTML 形式的代码:
<form [formGroup]="carForm">
<ion-item>
<ion-label stacked>car name</ion-label>
<ion-input type="text" [(ngModel)]="carname" formControlName="name"></ion-input>
</ion-item>
</form>
这是我的模拟(目前)服务调用,在设置绑定到输入的 carname 值后,我订阅了表单更改
setTimeout(()=>{
this.carname = "BMW";
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}, 44)
这里的问题是,即使我没有触及表单,this.changesMade 也会设置为 true。
注意:如果我在 ngAfterViewInit 中移动代码的订阅部分,它仍然会将 changesMade 设置为 true,即使我没有修改输入:
ngOnInit(){
//simulated server call
setTimeout(()=>{
this.carname = "BMW";
}, 44)
}
ngAfterViewInit(){
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}
我创建了一个 STACKBLITZ 来演示这个问题。我怎样才能让它执行 this.changesMade = true;
只有当我实际触摸 UI 中的输入时?
这里的问题是您混合了反应形式和 ngModel
。由于您在模板中使用了 ngModel
并在组件中设置了 this.carName = 'BMW'
,这会触发更改检测并且 formGroup
得到更新并且您的 changesMade
标志变为真。删除 ngModel
并使用反应式表单 API 获取表单值:https://angular.io/guide/reactive-forms#reactive-forms-api.
我更新了 STACKBLITZ:https://stackblitz.com/edit/ionic-qkjeu6?file=pages%2Fhome%2Fhome.ts
您以一种形式使用两种方法:
你需要select一个。
这个反应形式的解决方案:
1.Remove 来自模板的 ngModel
<ion-input type="text" formControlName="name"></ion-input>
2.Add rxjs/first 更新更改一次并自动退订
import 'rxjs/add/operator/first';
3.Remove carName 属性 来自您的组件并使用 patchValue
进行更新
ngOnInit() {
//simulated server call
setTimeout(() => {
this.carForm.patchValue({ name: 'BMW' })
this.carForm.valueChanges.first().subscribe(val => {
this.changesMade = true;
});
}, 44)
}
因此,通过将订阅放在调用堆栈的末尾(使用 setTimeout(0)),一切似乎都按预期工作:
//simulated server call
setTimeout(()=>{
this.carname = "BMW";
setTimeout(function(){
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}.bind(this), 0)
}, 44)
这里 STACKBLITZ 证明它有效。
更新
由于在 ngModel 中使用反应式表单 deprecated in Angular 6+,因此在类似用例中最好将反应式表单替换为模板驱动的表单。
我正在使用 Angular 表单,我想使用它们内置的更改检测来实现我的应用程序中的功能。当用户单击按钮时,如果 he/she 对表单进行了任何更改,他应该只会看到一个对话框。
我更改了变量:
private changesMade: boolean;
这是我的形式的 TS 代码:
this.carForm = new FormGroup({
name: new FormControl('', [
Validators.required,
Validators.pattern('[a-zA-Z ]*'),
Validators.minLength(1),
Validators.maxLength(10)
])});
这是我的 HTML 形式的代码:
<form [formGroup]="carForm">
<ion-item>
<ion-label stacked>car name</ion-label>
<ion-input type="text" [(ngModel)]="carname" formControlName="name"></ion-input>
</ion-item>
</form>
这是我的模拟(目前)服务调用,在设置绑定到输入的 carname 值后,我订阅了表单更改
setTimeout(()=>{
this.carname = "BMW";
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}, 44)
这里的问题是,即使我没有触及表单,this.changesMade 也会设置为 true。
注意:如果我在 ngAfterViewInit 中移动代码的订阅部分,它仍然会将 changesMade 设置为 true,即使我没有修改输入:
ngOnInit(){
//simulated server call
setTimeout(()=>{
this.carname = "BMW";
}, 44)
}
ngAfterViewInit(){
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}
我创建了一个 STACKBLITZ 来演示这个问题。我怎样才能让它执行 this.changesMade = true;
只有当我实际触摸 UI 中的输入时?
这里的问题是您混合了反应形式和 ngModel
。由于您在模板中使用了 ngModel
并在组件中设置了 this.carName = 'BMW'
,这会触发更改检测并且 formGroup
得到更新并且您的 changesMade
标志变为真。删除 ngModel
并使用反应式表单 API 获取表单值:https://angular.io/guide/reactive-forms#reactive-forms-api.
我更新了 STACKBLITZ:https://stackblitz.com/edit/ionic-qkjeu6?file=pages%2Fhome%2Fhome.ts
您以一种形式使用两种方法:
你需要select一个。
这个反应形式的解决方案:
1.Remove 来自模板的 ngModel
<ion-input type="text" formControlName="name"></ion-input>
2.Add rxjs/first 更新更改一次并自动退订
import 'rxjs/add/operator/first';
3.Remove carName 属性 来自您的组件并使用 patchValue
进行更新ngOnInit() {
//simulated server call
setTimeout(() => {
this.carForm.patchValue({ name: 'BMW' })
this.carForm.valueChanges.first().subscribe(val => {
this.changesMade = true;
});
}, 44)
}
因此,通过将订阅放在调用堆栈的末尾(使用 setTimeout(0)),一切似乎都按预期工作:
//simulated server call
setTimeout(()=>{
this.carname = "BMW";
setTimeout(function(){
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}.bind(this), 0)
}, 44)
这里 STACKBLITZ 证明它有效。
更新
由于在 ngModel 中使用反应式表单 deprecated in Angular 6+,因此在类似用例中最好将反应式表单替换为模板驱动的表单。