I created a Reactive Form in Angular 16, and added Bootstrap validation to it, normal built-in validators work fine, adding a custom validator also adds the error to the errors
array but Bootstrap still shows the input element as valid.
bootstrap-form.component.html:
<div class="container">
<div class="row">
<div class="col">
<h2 class="text-center fs-3 semibold">
{{ loginForm.value | json }}
</h2>
<form class="needs-validation" [formGroup]="loginForm" novalidate>
<div class="mt-4">
<label for="username-input" class="form-label fs-4">
username
</label>
<input
type="text"
id="username-input"
placeholder="username"
class="form-control mt-2"
formControlName="username"
required
/>
<div
class="invalid-feedback"
*ngIf="
loginForm.controls['username'].hasError('required')
"
>
username cannot be empty
</div>
</div>
<div class="mt-4">
<label for="password-input" class="form-label fs-4">
password
</label>
<input
type="password"
id="password-input"
placeholder="password"
class="form-control mt-2"
formControlName="password"
required
/>
<div
class="invalid-feedback"
*ngIf="
loginForm.controls['password'].hasError('required')
"
>
password cannot be empty
</div>
<div
class="invalid-feedback"
*ngIf="
loginForm.controls['password'].errors?.['passwordInvalid']
"
>
password cannot be less than 8 characters
</div>
<h3 class="fs-6">
{{ loginForm.controls["password"].errors | json }}
</h3>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary col-12">
login
</button>
</div>
</form>
</div>
</div>
</div>
bootstrap-form.component.ts:
import { Component, OnInit } from '@angular/core';
import {
AbstractControl,
FormBuilder,
FormControl,
FormGroup,
Validators,
} from '@angular/forms';
@Component({
selector: 'app-bootstrap-form',
templateUrl: './bootstrap-form.component.html',
styleUrls: ['./bootstrap-form.component.css'],
})
export class BootstrapFormComponent implements OnInit {
loginForm: FormGroup;
constructor(private formBuilderService: FormBuilder) {
this.loginForm = this.formBuilderService.group({
username: ['', [Validators.required]],
password: ['', [Validators.required, validatePassword]],
phoneNumber: ['', [Validators.required]],
});
}
ngOnInit(): void {
let form = document.querySelector('form') as HTMLFormElement;
form.addEventListener('submit', (submitEvent: SubmitEvent) => {
if (!form.checkValidity()) {
submitEvent.preventDefault();
submitEvent.stopPropagation();
}
form.classList.add('was-validated');
});
}
}
export function validatePassword(
formControl: AbstractControl
): { [key: string]: any } | null {
if (formControl.value && formControl.value.length < 8) {
return { passwordInvalid: true };
}
return null;
}
As you can see in the attached screenshots, the errors
array has a nerror but Bootstrap still shows it in green.
I just tried out this code, and I can't understand what's wrong here so I don't know what to try out.
According to Form validation in Bootstrap docs,
Although the Reactive form throws an error for the
password
field, it doesn't set the error in the constraint validation API.Approach 1: Use
minLength
attributeFrom the
validatePassword
function, you are validating the password minimum length, you can add theminLength="8"
attribute to the<input>
element.Note that, you can replace the
validatePassword
withValidators.minLength(8)
for the form control validationApproach 2: Update the error message to Validation API
If you are keen to use the Angular Reactive Form built-in/custom validation without the HTML attribute for the constraint validation API, you need to update the error message in the constraint validation API for each
<input>
element viasetCustomValidity(error)
.Demo @ StackBlitz