Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 reactive forms show error messages based on validation fail condition

I want to mention that i am using separate generic component, to display errors, so I am not putting them directly inside of html to avoid repetition, so I can't chain and hardcode conditional directly in template.

I have this field and two validations applied:

this.username = new FormControl('', [ Validators.minLength(5), Validators.required ]); 

How do I show validation error message for each of validations? Let's say I want to show both errors if nothing is in field on submit:
"Minimum length is 5"
"Field is required"

And then if you put something inside it should only show:
"Minimum length is 5"

This is an example but, my real life example is comparing two email fields, if they are the same, so if email is not correct is should show:
"Email is not correct"
"Email is not the same as first email field"

So if email is correct and emails are not the same should only show:
"Email is not the same as first email field"

I have validations working if not passed, but I am not sure how to show separately if one validation passed and another one not, because I have to properly append the real reason why it failed and not put some generic reason for both.

Full example:

Component for error display:

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-field-error-display',
  templateUrl: './field.error.display.component.html',
  styleUrls: ['./field.error.display.component.css']
})
export class FieldErrorDisplayComponent
{
    @Input() errorMsg: string;
    @Input() displayError: boolean;
}

Component html:

<div *ngIf="displayError" >
  <small>{{errorMsg}}</small>
</div>

Usage of erorr display in Register.html:

<form [formGroup]="_form" (ngSubmit)="register()">
<h4>Create a new account</h4>
<div class="form-group">
  <label for="email">Email Address</label>
  <input class="form-control" name="email" formControlName="email" />
  <app-field-error-display [displayError]="formValidationService.IsFieldValid(_form,'email')" errorMsg="Please insert correct email"></app-field-error-display>
</div>
<div class="form-group">
  <label for="emailConfirm">Email Address Confirm</label>
  <input class="form-control" name="emailConfirm" formControlName="emailConfirm" />
  <app-field-error-display [displayError]="formValidationService.IsFieldValid(_form,'emailConfirm')" errorMsg="Please insert correct email"></app-field-error-display>
</div>
<div class="form-group">
  <label for="password">Password</label>
  <input class="form-control" name="password" formControlName="password" />
  <app-field-error-display [displayError]="formValidationService.IsFieldValid(_form,'password')" errorMsg="Please insert password"></app-field-error-display>
</div>
<button type="submit" class="btn btn-default">Create Account</button>
</form>
<div *ngIf="_registered" class="alert alert-success box-msg" role="alert">
  <strong>Account registered!</strong> You will be redirected in sec
</div>

Register component:

ngOnInit() {
    this._form = this._formBuilder.group({
        email: ['', [Validators.required, Validators.email]],
        emailConfirm: ['', [Validators.required, Validators.email, MatchOtherValidator.Validate('email')]],
        password: ['', [Validators.required]]
    });

    this._registerModel = new RegisterModel();
}

Custom match other validator:

import { FormControl } from '@angular/forms';

export class MatchOtherValidator {
    static Validate(otherControlName: string) {

        let thisControl: FormControl;
        let otherControl: FormControl;

        return function matchOtherValidate(control: FormControl) {

            if (!control.parent) {
                return null;
            }

            // Initializing the validator.
            if (!thisControl) {
                thisControl = control;
                otherControl = control.parent.get(otherControlName) as FormControl;
                if (!otherControl) {
                    throw new Error('matchOtherValidator(): other control is not found in parent group');
                }
                otherControl.valueChanges.subscribe(() => {
                    thisControl.updateValueAndValidity();
                });
            }

            if (!otherControl) {
                return null;
            }

            if (otherControl.value !== thisControl.value) {
                return {
                    matchOther: true
                };
            }

            return null;

        }
    }
}

Form validation service has this method:

public IsFieldValid(form: FormGroup, field: string){
    return !form.get(field).valid && form.get(field).dirty;
}
like image 554
sensei Avatar asked Oct 29 '17 14:10

sensei


People also ask

How do you show error in reactive form?

When multiple validations are involved in a single formControl, we need to put multiple *ngIf in the HTML and bind the respective validator's error messages which makes the code clumsy.

How do I add a validation message in reactive form?

html file, add the ngIf directive to show the message when the form is submitted and the required validator is true. Save the changes and run the app. Click on the sign-in button without entering the first name and you will be able to see the required validation message.

How do you display error message below input field in HTML?

To customize the appearance and text of these messages, you must use JavaScript; there is no way to do it using just HTML and CSS. HTML5 provides the constraint validation API to check and customize the state of a form element. var email = document. getElementById("mail"); email.

How do I display mat error?

Error messages can be shown under the form field underline by adding mat-error elements inside the form field. Errors are hidden initially and will be displayed on invalid form fields after the user has interacted with the element or the parent form has been submitted.


2 Answers

Your code only checks if the form control is dirty and invalid. But you want to check if a specific validation fails. So you need to pass an additional error argument ('required', 'minlength', etc.), and use

form.get(field).hasError(error)
like image 23
JB Nizet Avatar answered Nov 07 '22 23:11

JB Nizet


I am answering this a little late, but I found a solution that is part of the angular materials modules that I really liked. If you implement your fields using "mat-form-field" you can easily display the error messages using a "mat-error" containing spans with an *ngIf.

I figured I should put it out there for other people trying to implement validator error messages. It makes the HTML a little beefy but it looks really nice.

<form [formGroup]="myForm" (ngSubmit)="submitForm()">
        <mat-form-field>
            <input matInput formControlName="user_input">
            <mat-error>
                <span *ngIf="myForm?.controls.user_input?.errors?.required">Required Field</span>
                <span *ngIf="myForm?.controls.user_input?.errors?.minLength">Minimum Length is 5</span>
            </mat-error>
        </mat-form-field>
</form>

The documentation is found here: https://material.angular.io/components/form-field/overview#error-messages

like image 61
Logan Kitchen Avatar answered Nov 07 '22 22:11

Logan Kitchen