Angular 形式:每个单独控件的值变化

Angular forms: value changes for each individual control

我想听取我的表单的值更改,但不是整个表单,而是仅针对已更改的表单控件。

例如,如果我的表单如下所示。

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

如果我订阅 valuechanges

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

然后在表单中填写名字会打印出整个表单值对象。

{firstName: 'input', lastName: '', ...}

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

{firstName: 'input'}

你可以试试这样的

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

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

自定义验证方法:

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};
};

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

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

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

以上片段摘自A thorough exploration of Angular Forms

由于这个原因,当 FormGroup child 的 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 中,如果我们考虑您的示例,_parent 可以引用 this.form FormGroup 实例,而 firstName FormControl 收到一些输入。


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

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},