如何在不重复FormControl

时间:2018-01-27 13:46:13

标签: angular angular5 angular-reactive-forms angular-forms

我有这些字段:

field1
field2
field3
field4

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

我需要更多验证:

- 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

如何将这些新的验证要求整合到构建的表单中?

我做想要做的是设置

formControl.valueChanges.subscribe(value => { });
每个字段的

然后有很多if / else。

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

2 个答案:

答案 0 :(得分:2)

您可以使用自定义验证程序执行此操作。 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;
  }
}

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

请注意,您无法在表单初始化中设置该验证程序,因为尚未定义基于它的字段。

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

this.myForm.get('field2').setValidators(this.greaterThan('field1'));

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

在此处查看此行动: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}};
    }
  }
}

答案 1 :(得分:0)

//你的.ts

  ngOnInit() {
    this.myForm = this.fb.group({
      field1: 0,
      field2: 0,
      field3: 0,
    }, { validator: this.customValidator }); //a unique validator

  }
  customValidator(formGroup: FormGroup) {         
    let errors:any={};
    let i:number=0;
    let valueBefore:any=null;
    Object.keys(formGroup.controls).forEach(field => {
      const control = formGroup.get(field);           
      if (valueBefore)
      {
        if (parseInt(control.value)<valueBefore)
        {
          let newError:any={['errorLess'+i]:true}  //create an object like,e.g. {errorLess1:true}
          errors={...errors,...newError};  //Concat errors
        }

      }
      valueBefore=parseInt(control.value);
      i++;
    });
    if (errors)
      return errors;
  }
}

.html喜欢

<form [formGroup]="myForm">
  field1:
  <input formControlName="field1">
  <br> field2:
  <input formControlName="field2">
  <div *ngIf="myForm.hasError('errorLess1')">Field 2 less that field 1</div>
  <br> field3:
  <input formControlName="field3">
  <div *ngIf="myForm.hasError('errorLess2')">Field 3 less that field 2</div>
</form>