Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send a custom form control validator a FormArray

I'm very simply trying to validate a control if its value matches a value within a FormArray.

I want to be clear that I do not want to validate the form or a FormGroup or a FormArray. This question is for learning how to pass parameters to a validator function and the validation of the addValue control.

Here is what I have in my custom validation service:

public form: FormGroup = this.fb.group({
    addValue: this.fb.control(null, [this.validatorService.duplicate(this.form.get('values'))]),
    values: this.fb.array([])
});

And the validator function

public duplicate(values: FormArray): ValidatorFn {
    return (control: AbstractControl): { [key: string]: boolean } | null => {
        for (let i = 0, j = values.length; i < j; i++ ) {
            if (control.value === values[i].value) {
                return { 'duplicate': true };
            }
        }
        return null;
    };
}

At this point I get an error where I add the validator with the FormArray as an argument:

Argument of type 'AbstractControl' is not assignable to parameter of type 'FormArray'. Type 'AbstractControl' is missing the following properties from type 'FormArray': controls, at, push, insert, and 5 more.ts(2345) (property) FormGroup.controls: { [key: string]: AbstractControl; }

Can someone show me how to send a FormArray into a validator function?

Here is a Stackblitz of the validator NOT getting the FormArray

like image 738
Ben Racicot Avatar asked Feb 15 '19 13:02

Ben Racicot


People also ask

How do I validate FormArray controls?

Validating Angular FormArray First you need to add the required validators while creating a new product form group inside the addProduct method. Now let's add a span element adjacent to the input control. Add the following CSS to the app. component.

How do you add a validator to FormControl dynamically?

We can add Validators dynamically using the SetValidators or SetAsyncValidators. This method is available to FormControl, FormGroup & FormArray. There are many use cases where it is required to add/remove validators dynamically to a FormControl or FormGroup.

How to validate a formarray using formbuilder?

A FormArray will be called validated only if its FormControl or FormGroup are validated. To provide a custom error messages on UI, we can fetch FormArray validation status in HTML template. On this page we will create a reactive form using FormBuilder and then we will validate and submit the form.

Do I need a custom validator for my form fields?

However, there may be form fields that require more complex or custom rules for validation. In those situations, you can use a custom validator. When using Reactive Forms in Angular, you define custom validators with functions.

How to access formarray validation errors for custom error messages?

To access validation state of FormArray and its elements, find the getter method for employees form array control. get employees(): FormArray { return this.teamForm.get('employees') as FormArray; } Now in HTML template we can access FormArray validation errors for custom error messages as following.

How to validate a formarray in Salesforce?

A FormArray is called validated only if its FormControl or FormGroup are validated. We can validate FormArray with synchronous and async validators. On this page we will create a reactive form using FormBuilder and validate it.


Video Answer


1 Answers

AbstractControl is the base class, simply cast you it:

public form: FormGroup = this.fb.group({
    addValue: this.fb.control(null, [this.validatorService.duplicate(this.form.get('values') as FormArray)]),
    values: this.fb.array([])
});

you could also sends values directly:

this.validatorService.duplicate(this.form ? this.form.get('values').value : []);

and

public duplicate(values: string[]): ValidatorFn {
    return (control: AbstractControl): { [key: string]: boolean } | null => {
        for (let i = 0, j = values.length; i < j; i++ ) {
            if (control.value === values[i]) {
                return { 'duplicate': true };
            }
        }
        return null;
    };
}

NEW ANSWER

Instead add a form Validator:

this.form = this.fb.group({
  addValue: this.fb.control(null),
  values: this.fb.array(['test2', 'test3'])
}, { validator: this.validatorService.duplicate2 });

using this code:

public duplicate2(control: AbstractControl): ValidationErrors | null {
    const newValue = control.get('addValue') ? control.get('addValue').value : null;
    const values = control.get('values') ? control.get('values').value : [];

    console.log("1 " + newValue);
    console.log(values);
    for (let i = 0, j = values.length; i < j; i++ ) {
              if (newValue === values[i]) {
                  return { 'duplicate2': true };
              }
          }
          return null;          
  }

and also change your validation:

<app-validator [control]="form"></app-validator>

see https://stackblitz.com/edit/send-validator-formarray-l8j7ys

you can pass the field names as parameter to the validator.

like image 173
moi_meme Avatar answered Oct 17 '22 16:10

moi_meme