1

i'm creating a form with FormBuilder and i want to add a Validator to a formGroup. Here is my code:

    this.myForm = fb.group({
        'name': ['', [Validators.maxLength(50), Validators.required]],
        'surname': ['', [Validators.maxLength(50), Validators.required]],
        'address': fb.group({
                'street': ['', Validators.maxLength(300)],
                'place': [''],
                'postalcode': ['']
        }),
        'phone': ['', [Validators.maxLength(25), phoneValidator]],
        'email': ['', emailValidator]
    });

I would like to conditionally add validators to some of the address's formControls on certain conditions.

So I added a validator in the following way:

        'address': fb.group({
                'street': ['', Validators.maxLength(300)],
                'place': [''],
                'postalcode': ['']
         }), { validator: fullAddressValidator })

Then i started to create a validator for the address FormGroup:

export const fullAddressValidator = (control:FormGroup) => {
    var street:FormControl = control.controls.street;
    var place:FormControl = control.controls.place;
    var postalcode:FormControl = control.controls.postalcode;

    if (my conditions are ok) {
        return null;
    } else {
        return { valid: false };
    }
};

I need to add the following conditions:

  1. If all fields are empty the form is valid
  2. If one of the field are filled in then all the fields must be required
  3. If place is instance of country (instead of city) the postalcode is optional
  4. If the postalcode is filled in then the zipValidator must be
    added to its formControl

So, it is possible to add Angular2 Validators to a FormGroup on certain conditions? If it does, how to implement my conditions? Can i use setValidators() and updateValueAndValidity() in the source code of another validator?

2 Answers 2

2

Create a function that takes a parameter and returns a validator function

export const fullAddressValidator = (condition) => (control:FormGroup) => {
    var street:FormControl = control.controls.street;
    var place:FormControl = control.controls.place;
    var postalcode:FormControl = control.controls.postalcode;

    if (my conditions are ok) {
        return null;
    } else {
        return { valid: false };
    }
};

and use it like

   'address': fb.group({
            'street': ['', Validators.maxLength(300)],
            'place': [''],
            'postalcode': ['']
     }), { validator: () => fullAddressValidator(condition) })
Sign up to request clarification or add additional context in comments.

8 Comments

What should i pass as parameter?
The condition. The condition can be a value, a method of the component or a class instance or a function. You can use it inside the validator to do additional checks that have access to a scope outside the validator. If you pass a method, the method can access the components state at the time of the validation check. Ensure you use ()=> arrow function syntax when you pass methods or functions around.
I'm currently have the whole FormGroup in my custom validator, so all conditions can be checked on its FormControls. Am i wrong?
I haven't found a way to get the dirty state from FormGroup. But you can use my approach to get it from the outside. I think subscribing to statusChanges from the group or controls provides that info. I wouldn't expect this to work with the FormGroup passed to the validator by Angular because it might be marked dirty before the validator is called.
Why do you want the dirty state? Do you know how can i add validators to formControl in my custom validator?
|
0

Yes, it's possible to set FormControl validators inside a FormGroup custom validator. Here is the solution to my needs:

export const fullAddressValidator = (control:FormGroup):any => {
    var street:FormControl = control.controls.street;
    var place:FormControl = control.controls.place;
    var postalcode:FormControl = control.controls.postalcode;

    if (!street.value && !place.value && !postalcode.value) {
        street.setValidators(null);
        street.updateValueAndValidity({onlySelf: true});
        place.setValidators(null);
        place.updateValueAndValidity({onlySelf: true});
        postalcode.setValidators(null);
        postalcode.updateValueAndValidity({onlySelf: true});

        return null;
    } else {
        street.setValidators([Validators.required, Validators.maxLength(300)]);
        street.updateValueAndValidity({onlySelf: true});
        place.setValidators([Validators.required]);
        place.updateValueAndValidity({onlySelf: true});
        if (place.value instanceof Country) {
            postalcode.setValidators(Validators.maxLength(5));
            postalcode.updateValueAndValidity({onlySelf: true});
        } else {
            postalcode.setValidators([zipValidator()]);
            postalcode.updateValueAndValidity({onlySelf: true});
        }
    }

    if (street.invalid || place.invalid || postalcode.invalid) {
        return {valid: false};

    } else {
        return null;
    }
};

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.