如何在不复制 FormControl 的情况下相互比较/验证多个多个字段

Pas*_*cal 2 angular angular-reactive-forms angular-forms angular5

我有这些领域:

field1
field2
field3
field4

this.form = this.formbuilder.group({
  'field1' = ['', [<control-specific-validations>]],
  'field2' = ['', [<control-specific-validations>]]
 }, { validator: isField1GreaterThanField2Validator}
 });
Run Code Online (Sandbox Code Playgroud)

我需要更多验证:

- field3.value must be greater than field4.value
- field3.value must be greater  than field2.value + 1
- field4.value must be less than field1.value
Run Code Online (Sandbox Code Playgroud)

您如何将这些新的验证要求集成到构建的表单中?

我确实希望做的是建立一个

formControl.valueChanges.subscribe(value => { });
Run Code Online (Sandbox Code Playgroud)

对于每个字段,然后在那里有很多 if/else。

然后我可以删除整个反应式表单模块,使用 2way-databinding 并在验证表达式为真时在 ui 中呈现错误字符串。

vin*_*nce 11

您可以使用自定义验证器来执行此操作。https://angular.io/guide/form-validation#custom-validators

这是您想要的工作示例:https : //stackblitz.com/edit/isgreaterthanotherfield-custom-validator

验证器函数本身如下所示:

greaterThan(field: string): ValidatorFn {
  return (control: AbstractControl): {[key: string]: any} => {
    const group = control.parent;
    const fieldToCompare = group.get(field);
    const isLessThan = Number(fieldToCompare.value) > Number(control.value);
    return isLessThan ? {'lessThan': {value: control.value}} : null;
  }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用parent控件上的属性来访问其他字段。

请注意,您不能在表单初始化中设置该验证器,因为您所基于的字段尚未定义。

this.myForm = this.fb.group({
  field1: 0,
  field2: 0
});

this.myForm.get('field2').setValidators(this.greaterThan('field1'));
Run Code Online (Sandbox Code Playgroud)

更新:我更进一步,实现了一个接受谓词函数的自定义验证器,因此您可以使用相同的验证器进行所有比较。

在这里查看它的实际效果:https : //stackblitz.com/edit/comparison-custom-validator

它使用与上面相同的方法,但更灵活一点,因为您可以传入任何比较。该示例没有考虑一些边缘情况,例如传递不存在的表单字段名称,如果您传递的表单字段实际上没有使用数字/类型不匹配等,但我相信超出了问题的范围。

这是一个有趣的问题,我喜欢研究它。

为了快速参考,以下是使用灵活的自定义验证器的整个组件的外观:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  myForm: FormGroup;

  field2HasError: boolean;
  field3HasError: boolean;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      field1: 0,
      field2: 0,
      field3: 0,
      field4: 0
    });

    const field1MustBeGreaterThanField2 = 
      this.comparison('field1', (field2Val, field1Val) => {
        return Number(field2Val) < Number(field1Val);
      });

    const field3MustBeGreaterThanField2Plus1 =
      this.comparison('field2', (field3Val, field2Val) => {
        return Number(field3Val) > (Number(field2Val) + 1);
      });

    this.myForm.get('field2').setValidators(field1MustBeGreaterThanField2);
    this.myForm.get('field3').setValidators(field3MustBeGreaterThanField2Plus1);

    this.myForm.get('field2').valueChanges.subscribe(() => {
      this.field2HasError = this.myForm.get('field2').hasError('comparison');
    });

    this.myForm.get('field3').valueChanges.subscribe(() => {
      this.field3HasError = this.myForm.get('field3').hasError('comparison');
    });
  }

  comparison(field: string, predicate: (fieldVal, fieldToCompareVal) => boolean): ValidatorFn {
    return (control: AbstractControl): {[key: string]: any} => {
      const group = control.parent;
      const fieldToCompare = group.get(field);
      console.log('fieldToCompare.value', fieldToCompare.value);
      console.log('field.value', control.value);
      const valid = predicate(control.value, fieldToCompare.value);
      return valid ? null : {'comparison': {value: control.value}};
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我不确定你是什么意思。您的问题是询问如何根据另一个表单控件中的值验证表单控件,而不会通过订阅值更改来强制设置错误。我已经演示了如何使用自定义验证器来做到这一点。您可以通过调整逻辑/条件来更改行为以满足您的需求,但一般方法已为您概述。 (2认同)