'Show error message after reactive form submission

On an Angular 8 Reactive form I have the following:

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <input id="name" type="text" formControlName="name">
  <span class="error" *ngIf="form.get('name').invalid && (form.get('name').dirty || form.get('name').touched)">
    Name error
  </span>
  <button type="submit" [disabled]="submitting">Send</button>
</form>

And the onSubmit is:

onSubmit() {

  this.submitting = true;

  if (this.form.valid) {
    // Submit form
  }

  this.submitting = false;

}

I am trying to configure the form as follows:

  1. Error messages are invisible when page loads;

  2. Error message for a field shows if the user types something invalid in the field;

  3. Error message shows if the form is submitted and there is an error on that field.

    I would like the form to be submitted even if it is invalid.

The problem I have is:

When the form is submitted, without touching the Name field, the error does not show after submission.


Solution 1:[1]

Option1:

You can add a isSubmitted bool variable to indicate whether or not the submit button was pressed by the user and set its value to true inside the onSubmit():

onSubmit() {
    this.isSubmitted = true;

    //rest of you code
}

and set the ngIf to this:

<span *ngIf="(form.get('name').invalid && form.get('name').touched) || 
             (form.get('name').untouched && isSubmitted)">
    Not Valid
</span> 
  1. Error messages are invisible when page loads;

The first line form.get('name').invalid && form.get('name').touched responsible.

  1. Error message for a field shows if the user types something invalid in the field;

Angular framework does this by default.

  1. Error message shows if the form is submitted and there is an error on that field.

The second line form.get('name').untouched && isSubmitted

Option2

As in this great article, on submitting you can iterate all of the controllers and set them as touched with:

Object.keys(this.form.controls).forEach(field => {
    const control = this.form.get(field);
    control.markAsTouched({ onlySelf: true });
});

So you could leave the markup a bit cleaner:

<span *ngIf="form.get('name').invalid && form.get('name').touched">
    Not Valid
</span>

Solution 2:[2]

This works for me in Angular 13. Working Demo here. Code on Github

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <input id="name" type="text" formControlName="name" />
  <div
    *ngIf="
      form.get('name')?.invalid &&
      (form.get('name')?.dirty || form.get('name')?.touched)
    "
    class="alert alert-danger"
  >
    <div *ngIf="form.get('name')?.errors?.['required']">Field is required.</div>
  </div>
  <button type="submit">Submit</button>
</form>

Use markAllAsTouched to show validation

onSubmit() {
  this.form.markAllAsTouched();
  if (this.form.valid) {
    console.log('Form is valid');
  } else {
    console.log('Form is not valid');
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shahar Shokrani
Solution 2