0

it's my first question on StackOverflow after years of using it, I'll try to do by best.

I have to develop a dynamic form with dynamic validations, for example in France (where I work), we have different adresses styles : a standard way with a road type / road name and an alternative format.

this.adress = this.fb.group({
  roadType: ['', Validators.required],
  roadName: ['', [ Validators.required,
                   Validators.minLength(5),
                   Validators.maxLength(20)] ],
  altRoad: ['', [ Validators.required,
                  Validators.maxLength(20)] ]
});

As you can see, at init, the 3 inputs are required. The rule I have to implement is to have at least 1 adress entered, so I put some watchers on valueChanges and when we type in an Input, the other adress format input has to lose its "required" validation.

this.altRoadSubscription = this.adress.get('altRoad').valueChanges.subscribe(val => {
        if (val && val !== ''){
            this.form.controls['roadType'].clearValidators();
            this.form.controls['roadType'].updateValueAndValidity();
            this.form.controls['roadName'].clearValidators();
            this.form.controls['roadName'].updateValueAndValidity();
        } else {

            this.form.controls['roadType'].setValidators(Validators.required);
            this.form.controls['roadName'].setValidators(Validators.required);
        }
    }
});

this.roadTypeSubscription = this.adress.get('roadType').valueChanges.subscribe(val => {
        const roadName = this.adress.controls['roadName'].value;

        if ((!val || val === '') && (!roadName || roadName === '')){
            this.adress.controls['altRoad'].setValidators(Validators.required);
        } else {
            this.adress.controls['altRoad'].clearValidators();
            this.adress.controls['altRoad'].updateValueAndValidity();
        }
});

this.roadNameSubscription = this.form.get('nomVoie').valueChanges.subscribe(val => {
  if ((!val || val === '') && (!roadType || roadType === '')){
      this.form.controls['altRoad'].setValidators(Validators.required);
  } else {
      this.form.controls['altRoad'].clearValidators();
      this.form.controls['altRoad'].updateValueAndValidity();
  }
})

The real big deal to play with are the other validators! I don't want to lose my minLength and maxLength validation when I switch between one adress to another and have to build a generic / standard method not to store the validators outside the formControl. (Everything will be managed from parents components)

How can I remove / add a single validator to the validators list without flushing every other validators by using a simple setValidators() method?

AND / OR

Is there a hack to get the current Validators list ? (to store them temporary and use setValidators() only with the validators we want to keep)

I saw this question that bring out an anwser but it seems like it doesn't work because of the type of the "control" used as a string instead of the AbstractControl.validator() prototype that expects an AbstractControl)

Sh. Pavel
  • 1,584
  • 15
  • 28
Pkr
  • 1

1 Answers1

0

Instead of dynamically setting the validators, you could keep them and update the errors.

This simply means that if the value of a field is truthy, then the other fields don't have the required error.

Something like this stackblitz.

this.a1.valueChanges.subscribe(value => {
   if(value) { this.a2.setErrors(this.updateRequiredError(this.a2.errors)); }
});

updateRequiredError(currentErrors: Object) {
  let ret = {... currentErrors};
  if (ret['required']) { delete ret['required']; }
  if (!Object.keys(ret).length) ret = null;
  return ret;
}