【问题标题】:Angular forms: value changes for each individual control角度形式:每个单独控件的值变化
【发布时间】:2021-09-25 00:39:17
【问题描述】:

我想听我的表单的 valuechanges,但不是整个表单,而只是被更改的 formcontrol。

例如,如果我的表单看起来像这样。

this.form = this._fb.group({
  firstName: [''],
  lastName: [''],
  ... // other stuff.
});

如果我随后订阅 valuechanges

this.form.valueChanges.subscribe((e) => {
  console.log(e);
});

然后在表单中填写名字将导致整个表单值对象的打印输出。

{firstName: '输入', lastName: '', ...}

但我想知道的是哪个表单控件(在本例中为firstName)在没有订阅每个单独的表单控件的情况下被更改。这样我想要的输出只有

{firstName: '输入'}

【问题讨论】:

标签: angular angular-forms


【解决方案1】:

首先,多个AbstractControls(例如FormControl,FormGroupFormArray)在内部存储为一棵树。

// FG - FormGroup
// FA - FormArray
// FC - FormControl

    FG
  /   \
FC    FG
    /    \
  FC     FA
        / | \
      FC FC FC

以上sn-p摘自A thorough exploration of Angular Forms

由于这个原因,FormGroup.valueChanges 会在 FormGroup 孩子的 valueChanges 发出时发出:

updateValueAndValidity (/* ... */) {
  /* ... */

  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);
  }
  
  /* ... */
}

above snippet 中,如果我们考虑您的示例,当firstName FormControl 收到一些输入时,_parent 可以引用this.form FormGroup 实例。


因此,实现您正在寻找的方法是这样的:

merge(
  ...Object.keys(this.form.controls).map(
    k => this.form.controls[k].valueChanges.pipe(
      // Getting a decent format: `{ formControlName: formControlValue }`
      map(v => ({ [k]: v })),
    )
  )
).subscribe(console.log)

FormGroup.controlsthis signature

public controls: {[key: string]: AbstractControl},

【讨论】:

    【解决方案2】:

    你可以试试这样的

      this.form.get("firstName").valueChanges.subscribe(selectedValue => {
          console.log(selectedValue)     
        })
         
    

    【讨论】:

    • 不,我明确表示我不想订阅每个单独的表单控件。在这个通用示例中,只有 2 个硬编码控件,但在我的真实案例场景中,还有更多控件,其名称事先不知道,但可以是动态的。
    • 是的。明白你的意思了。请点击此链接 - stackoverflow.com/questions/56729248/…
    【解决方案3】:

    有多种方式可以监听表单控件的变化:

    自定义验证方法:

    this.form = this._fb.group({
      firstName: ['', [this.fieldValidator]],
      lastName: [''],
      ... // other stuff.
    });
    
    fieldValidator(control: FormControl) {
         // control?.value available here
         // return null
    }
    

    或 交叉验证方法:

    this.form = this._fb.group({
      firstName: [''],
      lastName: [''],
      ... // other stuff.
    }, { validators: exampleValidator});
    
    export const exampleValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
      const firstName = control.get('firstName');
      // firstName?.value available here, etc
      // return condition ? null : { inValid: true};
    };
    

    【讨论】:

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