3

I'm trying to compare two input values in a custom validator. There should be an error if the minValue is greater than the maxValue.

FormGroup:

    sumFormGroup = this.formBuilder.group({
     from: ['', [Validators.min(0), sumValidator]],
     to: ['', [Validators.min(0), sumValidator]]
  });

custom validator:

 function sumValidator (control: AbstractControl):{[key: string]: boolean} | null {
   let minValue = control.get(this.sumFormGroup.get('from')).value;
   let maxValue = control.get(this.sumFormGroup.get('to')).value;
   if(minValue != maxValue){
    return {'ageValidator': true}
  }
  return null;
};

Error in browser console:

ERROR TypeError: Cannot read property 'sumFormGroup' of undefined
    at sumValidator in bla.ts
    (...)

Can anyone help? Thank you

pokly
  • 111
  • 2
  • 9
  • Since this function starts with `function`, `this.` does not refer to the class the function is defined in. That being said, are the other controls within the same form? – Silvermind Jul 14 '20 at 08:15
  • What other controls do you mean? I'm a beginner in angular, sorry. I don't know exactly what you mean – pokly Jul 14 '20 at 08:28
  • remove the function keyword from your `sumValidator` function – Piyush Jul 14 '20 at 09:03
  • What should I do instead? It won't find sumValidator anymore -> "Cannot find name 'sumValidator'" – pokly Jul 14 '20 at 09:08
  • While calling the function you would use `this.sumValidator` – Piyush Jul 14 '20 at 09:13

1 Answers1

4

Making the validation 'more' pure would help. Also I would suggest making two validations for this one.

function smallerThan(otherControlName: string) {
    return (control: AbstractControl): { [key: string]: boolean } | null => {
        if (!control.parent) {
            return null; // Control is not yet associated with a parent.
        }
        const thisValue = control.value;
        const otherValue = control.parent.get(otherControlName).value;
        if (thisValue < otherValue) {
            return null;
        }

        return {
            'smallerthan': true
        }
    };
}

function greaterThan(otherControlName: string) {
    return (control: AbstractControl): { [key: string]: boolean } | null => {
        if (!control.parent) {
            return null; // Control is not yet associated with a parent.
        }
        const thisValue = control.value;
        const otherValue = control.parent.get(otherControlName).value;
        if (thisValue > otherValue) {
            return null;
        }

        return {
            'greaterthan': true
        }
    };
}

Usage:

sumFormGroup = this.formBuilder.group({
    from: ['', [Validators.min(0), smallerThan('to')]],
    to: ['', [Validators.min(0), greaterThan('from')]]
 });

Perhaps you also need to take into account that the values may not be equal, but you could easily create two more validators called smallerThanOrEquals and greaterThanOrEquals.

If you wish to sync the validations, you could try to do it in the following way in your component:

ngOnInit() {
    // Example in the init, but make sure this.sumFormGroup is already created. 
    this.sumFormGroup.get('from').valueChanges.subscribe(() => this.sumFormGroup.get('to').updateValueAndValidity({ onlySelf: true, emitEvent: false }));
    this.sumFormGroup.get('to').valueChanges.subscribe(() => this.sumFormGroup.get('from').updateValueAndValidity({ onlySelf: true, emitEvent: false }));
}
Silvermind
  • 5,791
  • 2
  • 24
  • 44
  • Thank you for your answer! Unfortunately I am still getting that error: ERROR TypeError: Cannot read property 'get' of undefined – pokly Jul 14 '20 at 08:34
  • 1
    @pokly Are you referring to `....parent.get(...)`? If so, Perhaps the validator is run before the form is associated. I have updated my answer. – Silvermind Jul 14 '20 at 09:03
  • 1
    Yes it's the parent.get(...). Thank you so much! – pokly Jul 14 '20 at 09:05
  • Excuse me, do you have an idea how I can "update" each input field after entering a new value into the other input field? Example: -minValue input: 10 -maxValue input: 5 (-> Validator shows error for the maxValue input, because its too low) - I delete the "5", but the maxValue field with the "null" is still showing the error. I would like to update it dynamically. When I delete the "wrong" number, the error should be gone – pokly Jul 14 '20 at 10:00
  • 1
    @pokly Check out my latest update. You could also use a single validator on the entire form, but that would also require you to manually refresh the validation I guess. – Silvermind Jul 14 '20 at 10:08
  • 1
    It's working, you're a hero I guess. Would like to give you more points and selected answers – pokly Jul 14 '20 at 11:10