smartmouse
smartmouse

Reputation: 14404

Angular2: how to create custom validator for FormGroup?

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?

Upvotes: 1

Views: 4332

Answers (2)

smartmouse
smartmouse

Reputation: 14404

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;
    }
};

Upvotes: 0

Günter Zöchbauer
Günter Zöchbauer

Reputation: 658225

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) })

Upvotes: 2

Related Questions