0
votes

I have to find if one of my formcontrols has a pattern error. If it has a pattern error, then I have to change the value of that formcontrol to null.

I wrote a recursive method that calls itself to check if one f the form control has a pattern error and then it finally returns true or false, But what I want is to change the value of that formcontrol to null

Here is my recursive function,

hasPatternError(form: AbstractControl, isRecursion = false): boolean {
        if (!isRecursion) {
            this.patternErrors = [];
        }
        if (form instanceof FormControl) {
            return form.hasError('pattern') === true ?? null;
        }
        if (form instanceof FormArray) {
            form?.controls?.forEach(e => {
                this.hasAnyPatternError(e, true);
            });
        }
        if (form instanceof FormGroup) {
            Object.keys(form.controls).forEach(key => {
                const error = this.hasAnyPatternError(form.get(key), true);
                if (error === true) {
                    this.patternErrors.push(error);
                }
            });
            return this.patternErrors.length > 0 ? true : false;
        }
}

This is my form, listening to value changes event. On the change event, I am calling the above recursive method to find if any of the form control has a pattern error but stuck on changing the value of that formcontrol to null.

Note: I want the method (hasPatternError) to return an object(that has error converted to null and not expecting the form to change realtime)

ngOnInit() {
    this.myForm = this.fb.group({
      name: [''],
      address: this.fb.group({
        street: [''],
        zip: [''],
        licenseNo: ['', [Validators.required, Validators.pattern(/^[a-z0-9]{10}$/i)]],
      })
    })
    this.myForm.valueChanges.subscribe(
      data => {
        console.log(this.hasAnyPatternError(this.myForm))
      }
    );
  }

Here is my code on stackblitz

2
It looks like that the easiest way to solve this is to have an array in your pattern checker that stores the actual controls that match the condition and return that. You can then simply loop through that array of controls and do a setValue(null) on them?MikeOne
@MikeOne Can you please show me how on the above stackblitz?anonymous
I’m sorry, I’m on mobile at the moment.. the key is, you are losing the reference to the actual control you’re testing.MikeOne
I have a complex nested formgroup with form arrayanonymous
I understand, but I guess in the end, you only need the controls. You function seems inconsistent a bit). It can return an array or a single (boolean) value (it also finds only one and then returns. The trick is, once you find a control that has the error, push the control itself to an array and return that..MikeOne

2 Answers

1
votes

You already have reference to the form and the control key when you push the error.

Set the value on the control at that time.

  • Because you are doing this with recursion, it seems to have some odd behavior when I played with it in your stackblitz.
  • But the point I wanted to make is that there is a setValue function on the control for this, just need to determine the best way to use it in your logic.
  • Might even need to explore debouncing the behavior etc to allow the user time to finish key strokes.

if (!form.controls[key]['controls'] && error === true) {
                    setTimeout(()=>{
                      form.controls[key].setValue('');
                    },3000)
                    this.patternErrors.push(error);
                }

I added a setTimeout to wait 3 seconds before setting value back to '' to simulate debounce... it appears to work, but this is not a proper solution, just illustrates the principal you need to explore to leverage setValue properly in your recursion.

STACKBLITZ

https://stackblitz.com/edit/ng-nested-formgroup-zet7ry?file=src/app/app.component.ts

1
votes

Instead of returning booleans indicating a pattern error, return the controls that have pattern errors.

findPatternErrors(formItem: AbstractControl): FormControl[] {
  if (formItem instanceof FormControl) {
    if (formItem.hasError('pattern')) {
      return [formItem];
    } 
    return [];
  } 

  if (formItem instanceof FormArray) {
    const patternErrors: FormControl[] = [];
    formItem.controls?.forEach(arrayItem => {
      const ctrls = this.findPatternErrors(arrayItem);
      Array.prototype.push.apply(patternErrors, ctrls);
    });
    return patternErrors;
  }

  if (formItem instanceof FormGroup) {
    const patternErrors: FormControl[] = [];
    Object.keys(formItem.controls).forEach(key => {
      const ctrls = this.findPatternErrors(formItem.get(key));
      if (ctrls.length) {
        Array.prototype.push.apply(patternErrors, ctrls);
      }
    });
    return patternErrors;
  }
}

https://stackblitz.com/edit/ng-nested-formgroup-fmhfcs?file=src/app/app.component.ts