Angular forms using custom validation and a dynamic value

风流意气都作罢 提交于 2021-01-29 19:54:02

问题


I am trying to create a custom reactive form validation that allows me to pass an array of data to check if a string already exists. I am able to do it one way, so that it would be a form level validation but I can't get it to work on an individual form control.

Form level validation

This will create the error on the whole form, not just that control

this.myForm = this.fb.group({
  name: ['', Validators.compose([
    Validators.required,
  ]),
  ],
}, {
  validator: (formGroup: FormGroup) => this.checkStringExists(
    formGroup.controls.name,
    this.arrayOfStrings,
  ),
});

Custom validation that allows me to take in the form control and check it against an array that is passed in.

checkStringExists(formInput: AbstractControl, names: string[]): { [s: string]: boolean } {
  if (names && names.length && formInput && formInput.value) {
    const isUnique = !names.find((name) => name === formInput);
    if (isUnique) {
      return { nameExists: true };
    }
  }
  return null;
}

Individual control validation (The way I would like to do this)

This will create the error only on the specific control

this.myForm = this.fb.group({
  name: ['', Validators.compose([
    Validators.required,
    this.checkStringExists(this.arrayOfStrings),
  ]),
  ],
});

Custom validation that allows me to take only the array as part of the Validators.compose[] Here

checkStringExists(names: string[]): ValidatorFn {
  return (formInput: AbstractControl): ValidationErrors | null => {
    if (names && names.length && formInput && formInput.value) {
      const isUnique = !names.find((name) => name === formInput);
      if (!isUnique) {
        return { nameExists: true };
      }
    }
    return null;
  };
}

This subscription sets the value for arrayOfStrings.

mySubscription.subscribe((value: string[]) => {
    this.arrayOfStrings = value;
  })

The problem I have is arrayOfStrings may update multiple times. if I use the validation the first way, the arrayOfStrings is up to date. If I use the validation the second way, arrayOfStrings is null/initial value.

I am trying to get this validation to work the second way, so that I can display validation based on an individual control, not if the whole form has this error. Does anyone know how I can pass this value and keep it up to date?

I also have the validation functions in a separate helper file for reusability across the app.

Here is an example


回答1:


Update

my bad! you can pass an array, an array is an inmutable value. so if you has

  export function findArray(array){
    return (control=>{
      return array.indexOf(control.value)<0?{error:'not match'}:null
    })
  }

  array=['one','two']
  control=new FormControl(null,findArray(this.array))

you can see a simple stackblitz

Really a validator can not has "dynamic" argument. so some like

foolValidator(name:string)
{
   return (control:AbstractControl)=>{
        return control.value!=name?{error:'it's not the name'}:null
   }
}
name="joe"
control=new FormControl(null,foolValidator(this.name))

Only take account 'joe', not the name of variable "name"

You can use bind(this), bind change the "scope", see e.g. this link

foolValidator() //see that you not pass the argument
{
   return (control:AbstractControl)=>{
        //see that you use "this.name"
        return control.value!=this.name?{error:'it's not the name'}:null
   }
}
name="joe"
control=new FormControl(null,foolValidator().bind(this))


来源:https://stackoverflow.com/questions/65813583/angular-forms-using-custom-validation-and-a-dynamic-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!