[英]Angular form change detection
I am using Angular forms, and I would like to use their built-in change detection to implement a functionality in my application. 我正在使用Angular表单,我想使用它们的内置更改检测在我的应用程序中实现功能。 When a user clicks a button, he should only see a dialog if he/she has made any changes in the form. 用户单击按钮时,只有在他/她对表单进行了任何更改时,他/她才应该看到对话框。
I have changesMade variable: 我有changesMade变量:
private changesMade: boolean;
This is my TS code of the form: 这是我的TS格式的代码:
this.carForm = new FormGroup({
name: new FormControl('', [
Validators.required,
Validators.pattern('[a-zA-Z ]*'),
Validators.minLength(1),
Validators.maxLength(10)
])});
This is my HTML code of the form: 这是我的以下形式的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>
Here is my simulated(for now) service call where I subscribe to form changes after I've set the value of carname, which is bound to the input 这是我的模拟(暂时)服务调用,在我设置了carname的值(该值绑定到输入)之后,我订阅了表单更改
setTimeout(()=>{
this.carname = "BMW";
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}, 44)
The problem here is that even though I haven't touched the form, this.changesMade gets set to true. 这里的问题是,即使我还没有触摸过表单,this.changesMade也会设置为true。
NOTE: If I move the subscribe part of the code in the ngAfterViewInit, it still sets the changesMade to true even though I haven't toushed the input: 注意:如果我在ngAfterViewInit中移动了代码的订阅部分,即使我没有按下输入,它仍会将changesMade设置为true:
ngOnInit(){
//simulated server call
setTimeout(()=>{
this.carname = "BMW";
}, 44)
}
ngAfterViewInit(){
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}
I have created a STACKBLITZ demonstrating the problem. 我创建了一个STACKBLITZ来演示问题。 How can I make it execute this.changesMade = true;
我如何使其执行this.changesMade = true;
only when I've actually physically touched the input in the UI? 仅当我实际触摸过UI中的输入时?
You use two approach in one form: 您以一种形式使用两种方法:
You need to select one. 您需要选择一个。
This solution with reactive forms: 此解决方案具有反应形式:
1.Remove ngModel from template 1.从模板中删除ngModel
<ion-input type="text" formControlName="name"></ion-input>
2.Add rxjs/first for update changesMade once and auto unsubscribe 2,添加rxjs / first进行更新更改一次创建并自动退订
import 'rxjs/add/operator/first';
3.Remove carName property from you component and update from with patchValue 3.从您的组件中删除carName属性,并使用patchValue更新
ngOnInit() {
//simulated server call
setTimeout(() => {
this.carForm.patchValue({ name: 'BMW' })
this.carForm.valueChanges.first().subscribe(val => {
this.changesMade = true;
});
}, 44)
}
The problem here is that you are mixing reactive forms and ngModel
. 这里的问题是您正在混合反应形式和ngModel
。 Since you have used ngModel
in your template and setting this.carName = 'BMW'
in your component, this triggers the change detection and the formGroup
gets updated and your changesMade
flag becomes true. 由于您已在模板中使用ngModel
并在组件中设置了this.carName = 'BMW'
,因此这会触发更改检测,并且formGroup
得到更新,并且changesMade
标志变为true。 Remove the ngModel
and get your form values using reactive form APIs: https://angular.io/guide/reactive-forms#reactive-forms-api . 删除ngModel
并使用反应性表单API获取表单值: https : ngModel
。
I have updated the STACKBLITZ: https://stackblitz.com/edit/ionic-qkjeu6?file=pages%2Fhome%2Fhome.ts 我已经更新了堆栈BLACKZIT: https ://stackblitz.com/edit/ionic-qkjeu6 ? file = pages%2Fhome%2Fhome.ts
So by putting the subscription at the end of the callstack (with setTimeout(0)) everything seems to be working as expected: 因此,通过将预订放在调用堆栈的末尾(使用setTimeout(0)),一切似乎都按预期方式工作:
//simulated server call
setTimeout(()=>{
this.carname = "BMW";
setTimeout(function(){
this.carForm.valueChanges.subscribe(val => {
this.changesMade = true;
});
}.bind(this), 0)
}, 44)
Here is a STACKBLITZ demonstrating that it works. 这是一个STACKBLITZ,表明它有效。
UPDATE UPDATE
Since using reactive forms with ngModel is deprecated in Angular 6+ , it's better to replace the reactive forms with template driven forms in similar use cases. 由于在Angular 6+中已不建议将反应式与ngModel一起使用 ,因此在类似的用例中,最好用模板驱动的形式来替换反应式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.