angularvalidationangular-reactive-formsangular-formsangular-validation

How to use updateValueAndValidity()


I have two form controls as min and max. At the beginning min has a default value of 1 and max is empty. I want that max be always greater than min, so I defined a custom validator, which works nicely.

I also want that, if the value of min is changed, and gets bigger than max, the error be shown. To achieve this, I am calling updateValueAndValidity() on the min.valueChanges:

this.form.controls['min'].valueChanges.subscribe(
   (checked: any) => {
       this.form.controls['max'].updateValueAndValidity();
    }
);

For single digit numbers, it works perfectly. But for multi digit numbers, it doesn't work! For example:

min = 5  & max = 4 ---> error is shown that max must be greater than min (correct behavior)
min = 23 & max = 3 ---> no error is shown, because the first digit of min (i.e., 2) is smaller than max(i.e., 3)! (wrong behavior)
min = 43 & max = 3 ---> error is shown that max must be greater than min, because the first digit of min (i.e., 4) is greater than max(i.e., 3)!

Does anyone have any idea what is going on?

Update:

Form definition:

ngOnChanges() {
    this.form.addControl('min', this.formBuilder.control(1, [Validators.required]),{ emitEvent: false });
    this.form.addControl('max', this.formBuilder.control('', [maxValidator()]), { emitEvent: false });

    this.form.controls['min'].valueChanges.subscribe(
        (checked: any) => {
            this.form.controls['max'].updateValueAndValidity();
        }
    );
}

Custom validator definition:


export function maxValidator(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
        let minValue = (control.parent as formGroup)?.get("min")!.value;
        let maxValue = control.value;
        if (maxValue >= minValue) {
            return null 
        }
        else {
            return { maxValid: true }
        }
    }
}


Solution

  • Since you are comparing string, I think the validations are going wrong, you can use the + (Unary Plus Operator) to convert the values to number before performing the validations, this will fix the issue.

    export function maxValidator(): ValidatorFn {
        return (control: AbstractControl): ValidationErrors | null => {
            let minValue = (control.parent as formGroup)?.get("min")?.value || 0;
            let maxValue = control?.value || 0;
            if ((+maxValue) >= (+minValue)) {
                return null 
            }
            else {
                return { maxValid: true }
            }
        }
    }
    

    Below is the validation you are making as number and as string.

    // min = 5  & max = 4 ---> error is shown that max must be greater than min (correct behavior)
    console.log("min = 5  & max = 4 - as number: ", 4 >= 5);
    console.log("min = 5  & max = 4 - as string: ", '4' >= '5'); 
    
    // min = 23 & max = 3 ---> no error is shown, because the first digit of min (i.e., 2) is smaller than max(i.e., 3)! (wrong behavior)
    console.log("min = 23 & max = 3 - as number: ", 3 >= 23);
    console.log("min = 23 & max = 3 - as string: ", '3' >= '23'); 
    // min = 43 & max = 3 ---> error is shown that max must be greater than min, because the first digit of min (i.e., 4) is greater than max(i.e., 3)!
    console.log("min = 43 & max = 3  - as number: ", 3 >= 43);
    console.log("min = 43 & max = 3  - as string: ", '3' >= '43');