Clearly password and confirmPassword don,t match but still no error is being shownISSUE: creating a password validator to cross check with confirm password if it does not matches(as shown in passwordvalidator.ts) the input field would be red due to visual error in class is-invalid and aslo displays a small tag representing "password don't match "
HTML CODE:
<div class="container-fluid">
<h2>Registration Form</h2>
{{registrationForm.value | json}}
<form [formGroup]="registrationForm">
<div class="form-group">
<label>Username</label>
<input [class.is-invalid]="userName?.invalid &&
userName?.touched" formControlName="userName" type="text" class="form-control">
<div *ngIf="userName?.invalid &&
userName?.touched">
<small *ngIf="userName?.errors?.['required']" class="text-danger">Username is required</small>
<small *ngIf="userName?.errors?.['minlength']" class="text-danger">Username must be of atleast 3
characters</small>
<small *ngIf="userName?.errors?.['forbiddenName']"
class="text-danger">{{userName.errors?.['forbiddenName'].value}} Username not allowed</small>
</div>
</div>
<div class="form-group">
<label>Email</label>
<button type="button" class="btn btn-secondary btn-sm m-2" (click)="addAlternateEmail()">Add e-mail</button>
<input [class.is-invalid]="email.invalid && email.touched" type="email" class="form-control" formControlName="email">
<small class="text-danger" [class.d-none]="email.valid || email.untouched">Email is required</small>
<div formArrayName="alternateEmails" *ngFor = "let email of alternateEmails.controls; let i=index">
<input type = "text" class ="form-control my-1" [formControlName]="i">
</div>
</div>
<div class = "from-check mb-3">
<input class="form-check-label" formControlName="subscribe" type="checkbox">
<label class="form-check-label">
Send me promotional offers
</label>
</div>
<div class="form-group">
<label>Password</label>
<input formControlName="password" type="password" class="form-control">
</div>
<div class="form-group">
<label>Confirm Password</label>
<input [class.is-invalid]="registrationForm.errors?.['misMatch'] " formControlName="confirmPassword" type="password" class="form-control">
<small class="text-danger" *ngIf="registrationForm.errors?.['misMatch']">Password do not match</small>
</div>
<div formGroupName="address">
<div class="form-group">
<label>City</label>
<input formControlName="city" type="text" class="form-control">
</div>
<div class="form-group">
<label>State</label>
<input formControlName="state" type="text" class="form-control">
</div>
<div class="form-group">
<label>Postal Code</label>
<input formControlName="postalCode" type="text" class="form-control">
</div>
</div>
<button class="btn btn-primary me-md-2" type="submit">Register</button>
<button (click)="loadApiData()" class="btn btn-secondary" type="button">Load API Data</button>
</form>
</div>
App.component.ts CODE
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
import { forbiddenNameValidator } from './shared/user-name.validator';
import { PasswordValidator } from './shared/password-validator';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
registrationForm!: FormGroup;
get userName() {
return this.registrationForm.get('userName');
}
get email() {
return this.registrationForm.get('email');
}
get alternateEmails(){
return this.registrationForm.get('alternateEmails') as FormArray;
}
addAlternateEmail(){
this.alternateEmails.push(this.fb.control(''));
}
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.registrationForm = this.fb.group({
userName: ['', [Validators.required, Validators.minLength(3), forbiddenNameValidator(/admin/)]],
email: [''],
subscribe: [false],
password: [''],
confirmPassword: [''],
address: this.fb.group({
city: [''],
state: [''],
postalCode: ['']
}),
alternateEmails: this.fb.array([]),
},
{ Validators: PasswordValidator });
this.registrationForm.get('subscribe').valueChanges
.subscribe(checkedValue => {
const email:any = this.registrationForm.get('email');
if (checkedValue) {
email.setValidators(Validators.required);
}
else {
email.clearValidators();
}
email.updateValueAndValidity();
})
}
loadApiData() {
this.registrationForm.patchValue({
userName: 'Bruce',
password: 'test',
confirmPassword: 'test',
});
}
}
Module.ts:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Passwordvalidator.ts CODE
import { AbstractControl} from "@angular/forms";
export function PasswordValidator(control: AbstractControl): {[key: string]: boolean} | null{
const password = control.get('password');
const confirmPassword = control.get('confirmPassword');
if(password.pristine || confirmPassword.pristine){
return null;
}
return password && confirmPassword && password.value !== confirmPassword.value ?
{misMatch: true} :
null;
}