I want to display one error at a time with reactive forms and angular material

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



I want to display one error at a time with reactive forms and angular material



I am using Angular reactive forms and Angular material.
My code is working good.
But I want to display one error at a time



My .html file code




<form [formGroup]="accountDetailsForm" novalidate (ngSubmit)="onSubmitAccountDetails(accountDetailsForm.value)">

<mat-form-field class="full-width">
<input matInput maxlength="25" placeholder="Username" formControlName="username" required>
<mat-error *ngFor="let validation of account_validation_messages.username">
<mat-error class="error-message" *ngIf="accountDetailsForm.get('username').hasError(validation.type) && (accountDetailsForm.get('username').dirty || accountDetailsForm.get('username').touched)">validation.message</mat-error>
</mat-error>
</mat-form-field>

<mat-form-field class="full-width">
<input matInput type="email" placeholder="Email" formControlName="email" required>
<mat-error *ngFor="let validation of account_validation_messages.email">
<mat-error class="error-message" *ngIf="accountDetailsForm.get('email').hasError(validation.type) && (accountDetailsForm.get('email').dirty || accountDetailsForm.get('email').touched)">validation.message</mat-error>
</mat-error>
</mat-form-field>


<div formGroupName="matching_passwords">
<mat-form-field class="full-width">
<input matInput type="password" placeholder="Password" formControlName="password" required>
<mat-error *ngFor="let validation of account_validation_messages.password">
<mat-error class="error-message" *ngIf="accountDetailsForm.get('matching_passwords').get('password').hasError(validation.type) && (accountDetailsForm.get('matching_passwords').get('password').dirty || accountDetailsForm.get('matching_passwords').get('password').touched)">validation.message</mat-error>
</mat-error>
</mat-form-field>

<mat-form-field class="full-width">
<input matInput type="password" placeholder="Confirm Password" formControlName="confirm_password" [errorStateMatcher]="parentErrorStateMatcher" required>
<mat-error *ngFor="let validation of account_validation_messages.confirm_password">
<mat-error class="error-message" *ngIf="(accountDetailsForm.get('matching_passwords').get('confirm_password').hasError(validation.type)|| accountDetailsForm.get('matching_passwords').hasError(validation.type)) && (accountDetailsForm.get('matching_passwords').get('confirm_password').dirty || accountDetailsForm.get('matching_passwords').get('confirm_password').touched)">validation.message</mat-error>
</mat-error>
</mat-form-field>

</div>

<mat-checkbox formControlName="terms">
I accept terms and conditions
</mat-checkbox>
<mat-error *ngFor="let validation of account_validation_messages.terms">
<mat-error class="error-message" *ngIf="accountDetailsForm.get('terms').hasError(validation.type) && (accountDetailsForm.get('terms').dirty || accountDetailsForm.get('terms').touched)">validation.message</mat-error>
</mat-error>

<button class="submit-btn" color="primary" mat-raised-button type="submit" [disabled]="!accountDetailsForm.valid">
Submit
</button>

</form>



My .ts file code



Here, I'm specifying error messages for error that




account_validation_messages =
'username': [
type: 'required', message: 'Username is required' ,
type: 'minlength', message: 'Username must be at least 5 characters long' ,
type: 'maxlength', message: 'Username cannot be more than 25 characters long' ,
type: 'pattern', message: 'Your username must contain only numbers and letters' ,
type: 'validUsername', message: 'Your username has already been taken'
],
'email': [
type: 'required', message: 'Email is required' ,
type: 'pattern', message: 'Enter a valid email'
],
'confirm_password': [
type: 'required', message: 'Confirm password is required' ,
type: 'areEqual', message: 'Password mismatch'
],
'password': [
type: 'required', message: 'Password is required' ,
type: 'minlength', message: 'Password must be at least 5 characters long' ,
type: 'pattern', message: 'Your password must contain at least one uppercase, one lowercase, and one number'
],
'terms': [
type: 'pattern', message: 'You must accept terms and conditions'
]




Validators for form




this.accountDetailsForm = this.fb.group(
username: new FormControl('', Validators.compose([
UsernameValidator.validUsername,
Validators.maxLength(25),
Validators.minLength(5),
Validators.pattern('^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$'),
Validators.required
])),
email: new FormControl('', Validators.compose([
Validators.required,
Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
])),
matching_passwords: this.matching_passwords_group,
terms: new FormControl(false, Validators.pattern('true'))
)



All is working fine but problem is that I'm using ngFor to display error but I want to display one error at a time with the help of mat-error.




2 Answers
2



You can use for loop in your ts file to find out errors.




In your .ts File

for (let c in this.account_validation_messages.controls)
this.account_validation_messages.controls[c].markAsTouched();


Remove this HTML Code and

<mat-error *ngFor="let validation of account_validation_messages.terms">
<mat-error class="error-message" *ngIf="accountDetailsForm.get('terms').hasError(validation.type) && (accountDetailsForm.get('terms').dirty || accountDetailsForm.get('terms').touched)">validation.message</mat-error>
</mat-error>

Replace with this:

<mat-error class="error-message" *ngIf="accountDetailsForm.get('terms').hasError(validation.type) && (accountDetailsForm.get('terms').dirty || accountDetailsForm.get('terms').touched)">validation.message</mat-error>



REFER DEMO PROJECT FOR BETTER UNDERSTANDING.



control-message.component.ts:


import OnInit from '@angular/core';
import Component, Input from '@angular/core';
import FormGroup, FormControl, AbstractControl from '@angular/forms';

import CustomValidationService from '../custom-validation.service'

@Component(
selector: 'app-control-message',
templateUrl: './control-message.component.html',
styleUrls: ['./control-message.component.css']
)
export class ControlMessageComponent implements OnInit

ngOnInit()


@Input() control: FormControl;

constructor()

/**
* This method is use to return validation errors
*/
get errorMessage()
for (let propertyName in this.control.errors)
if (this.control.errors.hasOwnProperty(propertyName) && this.control.touched)
return CustomValidationService.getValidatorErrorMessage(this.getName(this.control), propertyName, this.control.errors[propertyName]);

if (this.control.valueChanges)
return CustomValidationService.showValidatorErrorMessage(propertyName, this.control.errors[propertyName])


return null;


/**
* This method used to find the control name
* @param control - AbstractControl
*/
private getName(control: AbstractControl): string



control-message.component.html:


<mat-error *ngIf="errorMessage !== null">
errorMessage
</mat-error>



application-form.html:


<h1>Common Error Message with Custom Validation Reactive Form</h1>

<form [formGroup]="accountDetailsForm" novalidate (ngSubmit)="onSubmitAccountDetails(accountDetailsForm.value)">
<div>
<mat-form-field class="full-width">
<input matInput maxlength="25" placeholder="Username" formControlName="username" required>
</mat-form-field>
<app-control-message [control]="accountDetailsForm.controls.username"></app-control-message>
</div>

<div>
<mat-form-field class="full-width">
<input matInput type="email" placeholder="Email" formControlName="email" required>
</mat-form-field>
<app-control-message [control]="accountDetailsForm.controls.email"></app-control-message>
</div>

<div>
<mat-form-field class="full-width">
<input matInput type="password" placeholder="Password" formControlName="password" required>
</mat-form-field>
<app-control-message [control]="accountDetailsForm.controls.password"></app-control-message>
</div>
<div>
<mat-form-field>
<input matInput type="password" placeholder="Confirm Password" formControlName="confirm_password" required>
</mat-form-field>

<app-control-message [control]="accountDetailsForm.controls.confirm_password"></app-control-message>
<mat-error *ngIf="accountDetailsForm.controls.password.value != accountDetailsForm.controls.confirm_password.value">
Password & Confrm Password Did not matched.
</mat-error>
</div>
<button class="submit-btn" color="primary" mat-raised-button type="submit" [disabled]="!accountDetailsForm.valid || (accountDetailsForm.controls.confirm_password != accountDetailsForm.controls.password)">
Submit</button>
</form>



application-form.component.ts:


accountDetailsForm: FormGroup;
constructor(private fb: FormBuilder)

ngOnInit()
this.createForm()

onSubmitAccountDetails(val)
console.log(val);


createForm()
this.accountDetailsForm = this.fb.group(
username: ['', [
Validators.maxLength(25),
Validators.minLength(5),
Validators.pattern('^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$'),
Validators.required
]],
email: [null, [
Validators.required,
Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
]],
password: [null, Validators.required],
confirm_password: [null, Validators.required]
)






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard