6

I have a form which changes its validation based on some value from the dropdown. If college A is selected then min percentage required in 60, if college B is selected then min percentage drops down to 55. Although I have figured out a way to get the min error in the template in so that I didn't have to hard code the percentage value in my template. Although I am not sure if this is the correct way or not.

<div formGroupName="marks">
  <div class="form-group">
    <label for="email" class="col-lg-3 control-label">Semester 1</label>
    <div class="col-lg-3">
      <input autocomplete="off"
             #sem1
             type="text"
             min="0"
             max="99"
             maxlength="1"
             maxlength="2"
             class="form-control"
             id="email"
             placeholder="Sem 1 (%)"
             (keypress)="onlyNumberKey($event)"
             formControlName="sem1">
      <span *ngIf="registrationForm.controls['marks'].controls['sem1'].hasError('required') &&
                   registrationForm.controls['marks'].controls['sem1'].touched"
                   class="text-danger">
        Sem 1 percentage required
      </span>
      <span *ngIf="registrationForm.controls['marks'].controls['sem1'].hasError('min') ||
                   registrationForm.controls['marks'].controls['sem1'].hasError('max') ||
                   registrationForm.controls['marks'].controls['sem1'].hasError('minlength')||
                   registrationForm.controls['marks'].controls['sem1'].hasError('maxlength') &&
                   registrationForm.controls['marks'].controls['sem1'].touched"
                   class="text-danger">
        Percenatge must be {{ registrationForm.get('marks.sem1')._errors.min.min }}  and above.
      </span>
    </div>
  </div>
</div>

Component

registrationForm = new FormGroup({
  college: new FormControl('', [
    Validators.required, dropDrownValidator
  ]),
  marks: new FormGroup({
    sem1: new FormControl('',
      [
        Validators.required,
        Validators.min(60),
        Validators.max(99),
        Validators.minLength(1),
        Validators.maxLength(2)
      ]
    )
  })
});

1 Answer 1

7

To achieve what you want, you have to watch the changes in your college control.

You can do this using (change) in template:

<select formControlName="college" (change)="handleChange($event.target.value)">
  ...
</select>

or even using valueChanges in component:

this.registrationForm.get('college').valueChanges.subscribe(college => this.handleChange(college));

And in your function, based on what college user selects, you can set the min value to your validator using AbstractControl#setValidators + AbstractControl#updateValueAndValidity (to apply ), as below:

handleChange(selectedCollege: string): void {
  const min = selectedCollege === 'CollegeA' ? 60 : 55;
  const control = this.registrationForm.get('marks.sem1');
  control.setValidators([Validators.required, customMin(min)]);
  control.updateValueAndValidity();
}

Tips:

1 - Since, you're using model-driven forms you shouldn't put validations in your HTML, keep it clean and put everything in component.

2 - You can use FormBuilder in order to simplify the construction of form (see the demo at the bottom).

3 - You should never access private properties like this:

{{ registrationForm.get('marks.sem1')._errors.min.min }}

Just use errors instead of _errors if you need to.

4 - You can simplify even more your markup:

Instead of:

<span *ngIf="registrationForm.controls['marks'].controls['sem1'].hasError('required') &&
             registrationForm.controls['marks'].controls['sem1'].touched" 
             class="text-danger">
  Sem 1 percentage required
</span>
<span *ngIf="registrationForm.controls['marks'].controls['sem1'].hasError('min') ||
             registrationForm.controls['marks'].controls['sem1'].hasError('max') ||
             registrationForm.controls['marks'].controls['sem1'].hasError('minlength')||
             registrationForm.controls['marks'].controls['sem1'].hasError('maxlength') &&
             registrationForm.controls['marks'].controls['sem1'].touched"
             class="text-danger">
  Percenatge must be {{ registrationForm.get('marks.sem1')._errors.min.min }}  and above.
</span>

You can have:

<div class="text-danger" *ngIf="registrationForm.get('marks.sem1').touched">
  <span *ngIf="registrationForm.hasError('required', 'marks.sem1')">
    Sem 1 percentage required
  </span>
  <span *ngIf="registrationForm.getError('customMin', 'marks.sem1') as error">
    Percentage must be greater than or equal to {{ error.min }}.
  </span>
</div>

WORKING DEMO

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.