tutorialfeed
tutorialfeed

Reputation: 1035

Angular: Show Reactive Form Validation Message with 'form.errors' or '!form.valid'

I have been using reactive form in my Angular project in many places and last week we decided to optimize our code a bit. During code review I have found an issue regarding showing form validation messages in HTML.

So I have used below code to show validation error messages:

<form [formGroup]="form">
  <div>
    <input formControlName="firstName">
    <div *ngIf="form.controls.firstName.errors && (form.controls.firstName.touched || form.controls.firstName.dirty)">
        This field is required
    </div>
  </div>
</form>

It seems fine, but what if I replace form.controls.firstName.errors with !form.controls.firstName.valid See below:

<form [formGroup]="form">
  <div>
    <input formControlName="firstName">
    <div *ngIf="!form.controls.firstName.valid && (form.controls.firstName.touched || form.controls.firstName.dirty)">
        This field is required
    </div>
  </div>
</form>

I couldn't see any difference at all but in my team some of team mates has opinion that we should use !form.controls.firstName.valid and we had long discussion on this small issue. I still didn't convince with my team mates. For me if form has an error then it's status will be invalid or form is invalid because it has an error.

Could anyone suggest me which option we should follow and is correct fundamentally.

Many thanks in advance.

Upvotes: 1

Views: 143

Answers (1)

Daniel Gimenez
Daniel Gimenez

Reputation: 20599

A validator function is going to return an object literal of errors if there is an error or null otherwise. The falsiness of the result is how angular know determines if a control is valid. So you can presume that the result will be functionally equivalent if you use .error or !...valid.

The being said using !...valid (or more appropriately .invalid) is the more definitive approach and if you look at Angular's examples that is how they do it.

I look at this way: Who knows in the future of if the behavior you're depending on is always going to be the same? There might be a legitimate case in the future where errors is null but the control is still invalid. Best to take the most explicit approach when there is no additional cost in doing so.

EDIT

Actually look at the source for AbstractControl potentially errors can be empty but the control can still be invalid depending on the implementation of the _anyControls() function:

get invalid(): boolean { return this.status === INVALID; }

/*...*/

private _calculateStatus(): string {
  if (this._allControlsDisabled()) return DISABLED;
  if (this.errors) return INVALID;
  if (this._anyControlsHaveStatus(PENDING)) return PENDING;
  /* if the condition below is true that means the control will be invalid
   * but errors will be null. */
  if (this._anyControlsHaveStatus(INVALID)) return INVALID;
  return VALID;
}

Given that conditions are possible that errors can be null but the control status still be invalid, then you should definitely be checking invalid and not errors.

Upvotes: 2

Related Questions