FormControl`s of nested FormGroup are ng-valid alt

2020-03-26 06:11发布

问题:

I have a nested form group called 'grades':

Although the nested form group 'grades' has the ng-invalid class applied the children form controls do have applied the ng-valid class.

Why is the invalidation not inherited from the nested form to its controls?

this.schoolyearForm = this.formBuilder.group({
  name: [this.createSchoolyear.name, [Validators.minLength(3), Validators.required]],
  endDate: [this.createSchoolyear.endDate, Validators.required],
  startDate: [this.createSchoolyear.startDate, Validators.required],
  grades: this.formBuilder.group({
    bestGrade: [this.createSchoolyear.bestGrade, Validators.required],
    worstGrade: [this.createSchoolyear.worstGrade, Validators.required]
  }, { validator: this.gradesCompare })
});


  gradesCompare(c: AbstractControl): { [key: string]: boolean } | null
  {
    let bestGradeControl = c.get("bestGrade");
    let worstGradeControl = c.get("worstGrade");

    if (bestGradeControl.pristine || worstGradeControl.pristine)
      return null;

    if (bestGradeControl.value === worstGradeControl.value)
    {
      return { "match": true };
    }
    return null;
  }

See the red and green borders:

On the FormControl`s are the css ng-invalid classes not applied:

.ng-valid:not(form)  {
  border-left: 5px solid #42A948; /* green */
}

.ng-invalid:not(form)  {
  border-left: 5px solid #a94442; /* red */
}

Therefore they are bordered green, but I expected them to be red!

UPDATE

I changed the plunkr of user Ben to this one:

https://plnkr.co/edit/VobcC0Qw1EBDytYdkzru?p=preview

It works as I wished it would work, but it seems like a workaround to me. The multiple ng-class expression are hard to understand...

Please Ben grab this plunkr as yours, post it as solution, but only if you think honestly you would also be satisfied with the solution. If not try to find a better solution please, now that you fully know my requirements.

Others are also welcome to join this challenge, now that you know how the validation/ui/error-messages should really behave.

回答1:

Technically, the specific form controls bestGrade and worstGrade are valid according to their own validators. Only their group has an error. Angular can't know you which controls you would want to invalidate if the group becomes invalid. You could make the information whether there was that specific group validation error onto the specific controls if you wished, and this would result in them being bordered red when they are invalid OR their group has the match error.

Without default, the order in which angular processes group validation and control validation would override any manual adding of ng-invalid on the control when the control becomes valid on its own (required condition fulfilled). This is why I am using another class here matchError rather than ng-invalid. Otherwise ng-invalid would be removed and replaced by ng-valid by the control validation after ng-invalid is added by ngClasses or equivalent class modification.

So instead of

<select formControlName="bestGrade">

you could use

<select [class.matchError]="schoolyearForm.get('grades').hasError('match')" formControlName="bestGrade">

in the same way, instead of

<select formControlName="worstGrade">

you can use

<select [class.matchError]="schoolyearForm.get('grades').hasError('match')" formControlName="worstGrade">

Edit: As OP still had issues while using select tags instead of input (read chat), I have recommended also removing the double pristine-ness requirement from the validator itself (by convention, we normally would check this where errors are displayed instead). Because the OP still has issues, I have prepared a plunkr demonstrating a working dummy (and ugly) version of his app to help investigate the issue.

The plunkr can be found at:

https://plnkr.co/edit/Gt5skDUOXfEaxsZreOkh

Edit 2: plnkr URL updated to deal with class setting order when validation are checked between group and individual group controls

Edit 3: Adjusted the answer here itself to reflect the OP's need for without defaults as was already setup in the latest plnkr from Edit 2