Issue
I am working on a reactive registration form in Angular 16.
I have made a custom validation to check if the values in the form fields password
and confirm_password
match:
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";
export const matchpassword : ValidatorFn = (control: AbstractControl):ValidationErrors|null => {
let password = control.get('password');
let confirm_password = control.get('confirm_password');
if (password && confirm_password && password?.value != confirm_password?.value) {
return { password_match : true }
}
return null;
}
In components\registration\registration.component.ts
I have:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { matchpassword } from "../../custom-validators/matchpassword.validator";
@Component({
selector: 'app-registration',
templateUrl: './registration.component.html',
styleUrls: ['./registration.component.scss']
})
export class RegistrationComponent implements OnInit {
public registrationForm!: FormGroup;
public isSuccess: Boolean = false;
constructor(private formBuilder: FormBuilder) { }
get form() { return this.registrationForm.controls }
public registerUser() {
if (this.registrationForm.status !== 'INVALID') {
// Show success alert
this.isSuccess = true;
// Reset form
this.registrationForm.reset();
} else {
return;
}
}
ngOnInit() {
this.registrationForm = this.formBuilder.group({
firstName: ['', [Validators.required, Validators.minLength(3)]],
lastName: ['', [Validators.required, Validators.minLength(3)]],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(6), matchpassword]],
confirm_password: ['', matchpassword],
terms: ['', Validators.requiredTrue],
}, {
validators: matchpassword
});
}
}
In components\registration\registration.component.html
I have:
<div *ngIf="isSuccess" class="alert alert-success alert-dismissible fade show text-center">
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
Your signup was successful!
</div>
<form
[formGroup]="registrationForm"
(ngSubmit)="registerUser()"
novalidate
>
<div class="form-element mb-2">
<label for="firstName" class="form-label"> First name </label>
<input
type="text"
id="firstName"
formControlName="firstName"
class="form-control form-control-sm"
/>
<span
class="invalid-feedback"
*ngIf="form['firstName']?.touched && form['firstName'].errors?.['required']"
>The <i>First name</i> field is required</span
>
<span
class="invalid-feedback"
*ngIf="form['firstName'].touched && form['firstName'].errors?.['minlength']"
>The <i>First name</i> must be at least 3 characters long</span
>
</div>
<div class="form-element mb-2">
<label for="lastName" class="form-label"> Last name </label>
<input
type="text"
id="lastName"
formControlName="lastName"
class="form-control form-control-sm"
/>
<span
class="invalid-feedback"
*ngIf="form['lastName'].touched && form['lastName'].errors?.['required']"
>The <i>Last name</i> field is required</span
>
<span
class="invalid-feedback"
*ngIf="form['lastName'].touched && form['lastName'].errors?.['minlength']"
>The <i>Last name</i> must be at least 3 characters long</span
>
</div>
<div class="form-element mb-2">
<label for="email" class="form-label"> Email address </label>
<input
type="email"
id="email"
formControlName="email"
class="form-control form-control-sm"
/>
<span
class="invalid-feedback"
*ngIf="form['email'].touched && form['email'].errors?.['required']"
>The <i>Email</i> field is required</span
>
<span
class="invalid-feedback"
*ngIf="form['email'].touched && form['email'].errors?.['email']"
>Please provide a valid email address</span
>
</div>
<div class="form-element mb-2">
<label for="password" class="form-label"> Password </label>
<input
type="password"
id="password"
formControlName="password"
class="form-control form-control-sm"
/>
<span
class="invalid-feedback"
*ngIf="form['password'].touched && form['password'].errors?.['required']"
>The <i>Password</i> field is required</span
>
<span
class="invalid-feedback"
*ngIf="form['password'].touched && form['password'].errors?.['minlength']"
>The password must have al least 6 characters</span
>
<span
class="invalid-feedback"
*ngIf="form['password'].touched && form['password'].errors?.['passwordcomplexity']"
>The password is not complex enough</span
>
<span
class="invalid-feedback"
*ngIf="form['password'].touched && registrationForm.errors?.['password_match']
"
>The passwords do not match</span
>
</div>
<div class="form-element mb-2">
<label for="confirm_password" class="form-label">
Confirm password
</label>
<input
type="password"
id="confirm_password"
formControlName="confirm_password"
class="form-control form-control-sm"
/>
</div>
<div class="form-element mb-2">
<input
type="checkbox"
formControlName="terms"
id="terms"
class="me-1"
/>
<span class="text-terms text-muted"
>I accept the
<a href="#" class="text-success">Terms & conditions</a></span
>
<span
class="invalid-feedback terms"
*ngIf="form['terms'].dirty && form['terms'].errors?.['required']"
>You must accept our Terms & conditions</span
>
</div>
<div class="pt-2">
<button
type="submit"
class="btn btn-sm btn-success w-100"
[disabled]="!registrationForm.valid"
>
Submit
</button>
</div>
</form>
The goal
If the passwords do not match, I want the error message "The passwords do not match" to show on the password field, as below:
The problem
Although the password is seen as invalid (the submit button is disabled), the error message does not show:
What am I doing wrong?
Solution
The matchpassword
validator needs to be added to the form group rather than to some single control. Adding a validator to a control doesn't give you access to the other controls.
this.registrationForm = this.formBuilder.group(
{
firstName: ['', [Validators.required, Validators.minLength(3)]],
lastName: ['', [Validators.required, Validators.minLength(3)]],
email: ['', [Validators.required, Validators.email]],
password: [
'',
[Validators.required, Validators.minLength(6), passwordcomplexity],
],
confirm_password: ['', Validators.required],
terms: ['', Validators.requiredTrue],
},
{
validators: [matchpassword],
}
);
After fixing that, you need to adjust your error message to be displayed when the form group has an error rather than the form control:
<span
class="invalid-feedback"
*ngIf="
form['password'].touched &&
registrationForm.errors?.['password_match']
"
>The passwords do not match</span
>
Updated stackblitz: https://stackblitz.com/edit/stackblitz-starters-wbynzu?file=src%2Fapp%2Fcomponents%2Fregistration%2Fregistration.component.ts
Note: There are now some issues with overlapping error messages, which I didn't fix, as this is not related to the question
Answered By - JSON Derulo
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.