简体   繁体   English

角形变化检测

[英]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)
}

Stackblitz example Stackblitz示例

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM