英文:
Angular Reactive Form with Bootstrap - Custom validation is not working in animation
问题
我在Angular 16中创建了一个响应式表单,并为其添加了Bootstrap验证。内置的验证器正常工作,但添加自定义验证器后,错误会添加到errors
数组中,但Bootstrap仍然将输入元素显示为有效。
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;
}
如附加的截图所示,errors
数组有一个错误,但Bootstrap仍然显示为绿色。
我刚刚尝试了这段代码,但我不明白问题出在哪里,所以不知道要尝试什么。
英文:
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.
答案1
得分: 1
> 所有现代浏览器都支持约束验证API,这是一系列用于验证表单控件的JavaScript方法。
尽管响应式表单对password
字段抛出错误,但它没有在约束验证API中设置错误。
方法1:使用minLength
属性
从validatePassword
函数中,您正在验证密码的最小长度,您可以在<input>
元素中添加minLength="8"
属性。
<input
type="password"
id="password-input"
placeholder="password"
class="form-control mt-2"
formControlName="password"
required
minlength="8"
/>
请注意,您可以将validatePassword
替换为Validators.minLength(8)
以进行表单控件验证
password: ['', [Validators.required, Validators.minLength(8)]]
方法2:更新验证API的错误消息
如果您希望在不使用约束验证API的HTML属性的情况下使用Angular响应式表单内置/自定义验证,您需要通过setCustomValidity(error)
为每个<input>
元素更新约束验证API中的错误消息。
<input
#passwordInput
type="password"
id="password-input"
placeholder="password"
class="form-control mt-2"
formControlName="password"
required
(input)="validatePasswordInput(passwordInput)"
/>
validatePasswordInput(passwordField: HTMLInputElement) {
if (this.loginForm.controls['password'].errors) {
for (let error in this.loginForm.controls['password'].errors)
passwordField.setCustomValidity(
this.loginForm.controls['password'].errors[error]
);
} else {
// No error
passwordField.setCustomValidity('');
}
}
英文:
According to Form validation in Bootstrap docs,
> All modern browsers support the constraint validation API, a series of JavaScript methods for validating form controls.
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
attribute
From the validatePassword
function, you are validating the password minimum length, you can add the minLength="8"
attribute to the <input>
element.
<input
type="password"
id="password-input"
placeholder="password"
class="form-control mt-2"
formControlName="password"
required
minlength="8"
/>
Note that, you can replace the validatePassword
with Validators.minLength(8)
for the form control validation
password: ['', [Validators.required, Validators.minLength(8)]]
Approach 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 via setCustomValidity(error)
.
<input
#passwordInput
type="password"
id="password-input"
placeholder="password"
class="form-control mt-2"
formControlName="password"
required
(input)="validatePasswordInput(passwordInput)"
/>
validatePasswordInput(passwordField: HTMLInputElement) {
if (this.loginForm.controls['password'].errors) {
for (let error in this.loginForm.controls['password'].errors)
passwordField.setCustomValidity(
this.loginForm.controls['password'].errors[error]
);
} else {
// No error
passwordField.setCustomValidity('');
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论