Angular formGroup如何检测表单是否真的在订阅中发生变化?

问题描述 投票:1回答:1

我想做一个函数,可以检测到Angular formGroup 实际上改变了它的值:

 subscribeToFormChanges() {
    const formSub = this.formGroup.valueChanges.subscribe(value => {
      console.log(this.formGroup.getRawValue());
      console.log(value);
      if (this.formGroup.getRawValue() == value) {
        console.log('equal');
      } else {
        console.log('not changed');
      }
    },
      (error) => {
        console.log(error)
      },
      () => {
        this.subs.add(formSub);
      })
  }

为什么?- 因为有一些选择,你可以选择相同的值,它将会是 .setValue 关于 control.

但它总是返回没有改变,即使我改变值。如何以正确的方式做?

第二种方法。

  subscribeToFormChanges() {
    const formSub = this.formGroup.valueChanges.pipe(startWith(null), pairwise()).subscribe(([prev, next]: [any, any]) => {
      if (prev == next) {
        console.log('equal');
      } else {
        console.log('not changed');
      }
    },
      (error) => {
        console.log(error)
      },
      () => {
        this.subs.add(formSub);
      })
  }

Returns not changed all the time

angular typescript angular-forms
1个回答
0
投票

你得到这些结果是因为你在比较两个不同的引用。

你可以用可视化的方式显示 表格控制树 如下:

// FG - FormGroup
// FC - FormControl

    FG
  /   \
 FC   FG
     /  \
   FC   FC <-- <select formControlName="yourSelect">

FormControl.setValue 被调用(例如由于用户的改变),它的所有祖先都必须被更新。通过 updated我的意思是更新 用户交互状态(touched, pristine 等)。) 调用验证器 和更新 有效期.

updateValueAndValidity 方法负责这样的事情。它是由 FormControl.setValue:

this._setInitialStatus();
this._updateValue();

if (this.enabled) {
  this._cancelExistingSubscription();
  (this as { errors: ValidationErrors | null }).errors = this._runValidator();
  (this as { status: string }).status = this._calculateStatus();

  if (this.status === VALID || this.status === PENDING) {
    this._runAsyncValidator(opts.emitEvent);
  }
}

if (opts.emitEvent !== false) {
  (this.valueChanges as EventEmitter<any>).emit(this.value);
  (this.statusChanges as EventEmitter<string>).emit(this.status);
}

if (this._parent && !opts.onlySelf) {
  this._parent.updateValueAndValidity(opts);
}

请注意,这种方法对以下情况是一样的: FormControl, FormArrayFormGroup.

正如你所看到的,这也是一个地方。this.valueChanges 发出。这意味着根节点(例如你的 formGroup 在例子中)最终将达到,你将收到的是 累积值 从所有其他的子孙(表格控制).

您感兴趣的对象被分配给了 this.value 其解决方法为 this._updateValue(),也就是 特定实体. జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ FormGroup,这就是确定数值的方法。

_updateValue(): void {
    (this as {value: any}).value = this._reduceValue();
  }

_reduceValue() {
  return this._reduceChildren(
    {}, (acc: { [k: string]: AbstractControl }, control: AbstractControl, name: string) => {
      if (control.enabled || this.disabled) {
        acc[name] = control.value;
      }
      return acc;
    });
}

从上面你可以看到 {},它是一个新的引用,与之前由 pairwise(). 所以,这应该可以解释为什么你总是得到这个结果。

解决这个问题的一个方法是在之前的对象值和当前的对象值之间进行深度比较。

另一种方法是防止树被更新,除非有新的值进来。这涉及到在 leaf 级(e.g FormControls). 你可以创建一个 自定义控制值接入器 并在那里做逻辑。

然而,我不认为 select 会发出 change 事件,如果选择了相同的值。演示.

如果你想探索Angular Forms,我很想推荐你去看看 本文.

© www.soinside.com 2019 - 2024. All rights reserved.