【问题标题】:Angular form change detection角度形式变化检测
【发布时间】:2018-09-13 11:24:26
【问题描述】:

我正在使用 Angular 表单,我想使用它们内置的更改检测来在我的应用程序中实现一项功能。当用户点击一个按钮时,只有在他/她对表单进行了任何更改时,他才会看到一个对话框。

我有 changesMade 变量:

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 中移动代码的 subscribe 部分,即使我没有修改输入,它仍然会将 changesMade 设置为 true:

  ngOnInit(){
    //simulated server call
    setTimeout(()=>{
      this.carname = "BMW";

    }, 44)
  }
      ngAfterViewInit(){
this.carForm.valueChanges.subscribe(val => {
      this.changesMade = true;
        });
    }

我创建了一个STACKBLITZ 来演示这个问题。仅当我实际触摸 UI 中的输入时,如何才能使其执行 this.changesMade = true;

【问题讨论】:

  • 为什么要手动设置 this.carname = "BMW"?由于您正在设置此值更改检测被触发并且您的标志变为真。如果您使用的是响应式表单,请删除 [(ngModel)]="carname"。

标签: angular ionic-framework rxjs ionic3 angular-forms


【解决方案1】:

您在一种形式中使用两种方法:

你需要选择一个。

这种反应形式的解决方案:

1.从模板中移除ngModel

<ion-input type="text" formControlName="name"></ion-input>

2.添加rxjs/first进行更新更改一次并自动退订

import 'rxjs/add/operator/first';

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

【讨论】:

    【解决方案2】:

    这里的问题是你混合了反应形式和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

    【讨论】:

    • 是的,但是在我将车名更改为“BMW”之后,我将订阅价​​值更改。我还需要将我的表单绑定到模型,所以这不是一个真正的选择
    【解决方案3】:

    因此,通过将订阅放在调用堆栈的末尾(使用 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+,因此在类似的用例中最好将响应式表单替换为模板驱动的表单。

    【讨论】:

      猜你喜欢
      • 2021-06-04
      • 1970-01-01
      • 2021-06-17
      • 1970-01-01
      • 2021-08-07
      • 2018-10-24
      • 1970-01-01
      • 2018-05-07
      • 1970-01-01
      相关资源
      最近更新 更多