表单验证
ABP Angular UI 中的响应式表单由 ngx-validate 进行验证,并且会根据验证规则和错误蓝本自动显示帮助文本。您无需在模板中添加任何元素或组件。该库会为您处理这一切。用户体验如下:
如何添加新的错误消息
您可以通过在根应用配置的 provideAbpThemeShared 函数内的 withValidationBluePrint 方法中传入验证选项来添加新的错误消息。
import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared';
export const appConfig: ApplicationConfig = {
providers: [
// ...
provideAbpThemeShared(
withValidationBluePrint({
uniqueUsername: "::AlreadyExists[{{ username }}]"
})
),
// ...
],
};
或者,您也可以在根配置中直接提供 VALIDATION_BLUEPRINTS 令牌。请注意不要忘记扩展 DEFAULT_VALIDATION_BLUEPRINTS。否则,内置的 ABP 验证消息将无法工作。
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
export const appConfig: ApplicationConfig = {
providers: [
{
provide: VALIDATION_BLUEPRINTS,
useValue: {
...DEFAULT_VALIDATION_BLUEPRINTS,
uniqueUsername: "::AlreadyExists[{{ username }}]",
},
},
// 其他提供程序
],
};
当验证器或异步验证器返回一个键与错误蓝本给定的键(此处为 uniqueUsername)相匹配的错误时,验证库将能够根据给定的键和插值参数进行本地化后显示错误消息。结果将如下所示:
在此示例中:
- 本地化键是
::AlreadyExists。 - 插值参数是
username。 - 本地化资源定义为
"AlreadyExists": "对不起,“{0}”已存在。"。 - 验证器应返回
{ uniqueUsername: { username: "admin" } }作为错误对象。
如何更改现有的错误消息
您可以通过在根应用配置中的 provideAbpThemeShared 中传递验证选项来覆盖现有的错误消息。假设您有一个针对必填输入的自定义本地化资源。
"RequiredInput": "哎呀!我们需要这个输入。"
要使用此消息而非内置的必填输入消息,您只需执行以下操作。
import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared';
export const appConfig: ApplicationConfig = {
providers: [
// ...
provideAbpThemeShared(
withValidationBluePrint({
required: "::RequiredInput",
})
),
// ...
],
};
或者,您也可以在根应用配置中直接提供 VALIDATION_BLUEPRINTS 令牌。请不要忘记扩展 DEFAULT_VALIDATION_BLUEPRINTS。否则,内置的 ABP 验证消息将无法工作。
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
export const appConfig: ApplicationConfig = {
providers: [
{
provide: VALIDATION_BLUEPRINTS,
useValue: {
...DEFAULT_VALIDATION_BLUEPRINTS,
required: "::RequiredInput",
},
},
// 其他提供程序
],
};
错误消息将如下所示:
如何在表单上禁用验证
如果您想手动验证表单,可以随时在其上禁用自动验证。您只需在表单元素上放置 skipValidation 属性即可。
<form [formGroup]="form" skipValidation>
<!-- 表单字段写在这里 -->
</form>
如何在特定字段上禁用验证
验证适用于任何带有 formControl 或 formControlName 指令的元素或组件。您可以通过在输入元素或组件上放置 skipValidation 属性来禁用特定字段的自动验证。
<input type="text" formControlName="name" skipValidation />
如何使用自定义错误组件
首先,构建一个自定义错误组件。扩展现有的 ValidationErrorComponent 会使这更容易。
import { LocalizationPipe } from "@abp/ng.core";
import { ValidationErrorComponent } from "@abp/ng.theme.basic";
import { CommonModule } from "@angular/common";
import { ChangeDetectionStrategy, Component } from "@angular/core";
@Component({
selector: "app-validation-error",
imports:[CommonModule, LocalizationPipe],
template: `
<div
class="font-weight-bold font-italic px-1 invalid-feedback"
*ngFor="let error of abpErrors; trackBy: trackByFn"
>
{{ error.message | abpLocalization: error.interpoliteParams }}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ErrorComponent extends ValidationErrorComponent {}
然后,在您的根配置中提供它。
import { VALIDATION_ERROR_TEMPLATE } from "@ngx-validate/core";
export const appConfig: ApplicationConfig = {
providers: [
// 其他提供程序
{
provide: VALIDATION_ERROR_TEMPLATE,
useValue: ErrorComponent,
},
],
};
现在错误消息将以粗体和斜体显示:
如何验证嵌套表单组
在 ABP Angular UI 中,有几种方法可以验证嵌套的表单组。下面是第一种也是最常见的方法,即使用嵌套响应式表单进行自动验证和错误消息显示。(第二种方法将在下一节中介绍。)
第一种方式:使用嵌套响应式表单进行自动验证和错误消息显示
ABP Angular UI 利用 Angular 的响应式表单和 ngx-validate 库,提供了强大、灵活且用户友好的表单验证体验。无论您是手动构建表单还是使用 ABP 的动态表单生成功能,验证和错误消息都是自动处理的。
主要特性
自动验证: 在您的 DTO 中定义的所有验证规则(例如
[Required]、[StringLength]、[EmailAddress]等)都会自动反映在 Angular 表单中。错误消息会在每个字段下方显示,无需任何额外的标记。嵌套表单组和动态字段: 对于复杂的数据结构,您可以使用嵌套的
FormGroup和FormArray结构对字段进行分组或管理动态列表。验证和错误显示对父控件和子控件都能无缝工作。动态和可扩展的表单: 借助 ABP 的可扩展性系统,您可以使用
generateFormFromProps等帮助程序动态生成表单,并使用abp-extensible-form组件来显示它们。这确保了所有实体属性(包括扩展属性)都包含在表单中,并且应用了它们的验证规则。无需额外的样板代码: 您不需要为验证添加自定义错误组件或指令。该系统开箱即用,包括嵌套和动态生成的控件。
实际示例:用户表单中的嵌套表单组
下面是 ABP Angular UI 中用户管理表单的一个真实示例,展示了嵌套表单结构和验证是如何实现的。此示例包括动态生成的字段(使用 abp-extensible-form)和使用 FormArray 和 FormGroup 的动态角色列表。
TypeScript: 构建表单
buildForm() {
const data = new FormPropData(this.injector, this.selected);
this.form = generateFormFromProps(data); // 从实体和扩展属性自动创建表单控件
this.service.getAssignableRoles().subscribe(({ items }) => {
this.roles = items;
if (this.roles) {
// 动态角色列表:嵌套的 FormArray 和 FormGroup
this.form.addControl(
'roleNames',
this.fb.array(
this.roles.map(role =>
this.fb.group({
[role.name as string]: [
this.selected?.id
? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id)
: role.isDefault,
],
}),
),
),
);
}
});
}
HTML: 显示表单
<abp-modal [(visible)]="isModalVisible" [busy]="modalBusy">
<ng-template #abpHeader>
<h3>{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }</h3>
</ng-template>
<ng-template #abpBody>
@if (form) {
<form [formGroup]="form" (ngSubmit)="save()">
<ul ngbNav #nav="ngbNav" class="nav-tabs">
<li ngbNavItem>
<a ngbNavLink>{ 'AbpIdentity::UserInformations' | abpLocalization }</a>
<ng-template ngbNavContent>
<!-- 自动显示所有实体字段及其验证 -->
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
</ng-template>
</li>
<li ngbNavItem>
<a ngbNavLink>{ 'AbpIdentity::Roles' | abpLocalization }</a>
<ng-template ngbNavContent>
<!-- 动态角色列表:嵌套的 FormArray 和 FormGroup -->
@for (roleGroup of roleGroups; track $index; let i = $index) {
<div class="form-check mb-2">
<abp-checkbox
[formControl]="roleGroup.controls[roles[i].name]"
[label]="roles[i].name"
></abp-checkbox>
</div>
}
</ng-template>
</li>
</ul>
<div class="mt-2 fade-in-top" [ngbNavOutlet]="nav"></div>
</form>
} @else {
<div class="text-center"><i class="fa fa-pulse fa-spinner" aria-hidden="true"></i></div>
}
</ng-template>
</abp-modal>
说明:
abp-extensible-form自动生成并显示所有实体字段及其验证。- 在角色选项卡中,每个角色由一个复选框表示,这些复选框在
FormArray中管理,每个复选框都是一个FormGroup。这是一个嵌套表单结构的实际示例。 - 所有验证和错误消息都会为主表单和嵌套组自动显示。
第二种方式:手动创建嵌套响应式表单(不使用 abp-extensible-form)
您也可以手动构建和验证嵌套表单组,而不使用 abp-extensible-form 或动态帮助程序。这种方法让您完全控制表单结构,对于自定义或非基于实体的表单非常有用。
示例:简单的手动嵌套 FormGroup
下面是一个简单的、通用的嵌套响应式表单示例。该表单包含一个用于个人资料信息的嵌套 FormGroup,并演示了如何应用验证规则。
TypeScript: 构建表单
import { Component, OnInit, inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NgxValidateCoreModule } from '@ngx-validate/core';
@Component({
selector: 'app-nested-form',
templateUrl: './nested-form.component.html',
standalone: true,
imports: [NgxValidateCoreModule],
})
export class NestedFormComponent implements OnInit {
form: FormGroup;
private fb = inject(FormBuilder);
ngOnInit() {
this.buildForm();
}
buildForm() {
this.form = this.fb.group({
userName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
profile: this.fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
}),
});
}
submit() {
if (this.form.invalid) {
return;
}
// 处理提交逻辑
}
}
HTML: 显示表单
<form [formGroup]="form" (ngSubmit)="submit()">
<div class="mb-3">
<label class="form-label">用户名</label>
<input type="text" class="form-control" formControlName="userName" />
</div>
<div class="mb-3">
<label class="form-label">邮箱</label>
<input type="email" class="form-control" formControlName="email" />
</div>
<div formGroupName="profile" class="card mt-3">
<div class="card-header">
<strong>个人资料详情</strong>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label">名</label>
<input type="text" class="form-control" formControlName="firstName" />
</div>
<div class="mb-3">
<label class="form-label">姓</label>
<input type="text" class="form-control" formControlName="lastName" />
</div>
</div>
</div>
<hr class="my-3" />
<div>
<abp-button buttonType="submit" iconClass="fa fa-save" [disabled]="form.invalid">
保存
</abp-button>
</div>
</form>
工作原理:
- 该表单包含主要字段(
userName、email)和一个嵌套的FormGroup(profile)。 profile组包含firstName和lastName字段,每个字段都有自己的验证规则。- 验证规则直接在表单构建器中定义。
- 错误消息和验证反馈由 ngx-validate 和 ABP Angular UI 自动处理,就像动态表单一样。
- 此结构确保验证能自动对主表单和嵌套组生效。
注意: 这种方法适用于自定义表单或当您希望完全控制表单结构时。它提供了与 ABP 动态表单类似的用户体验和验证行为,但在表单布局和逻辑上提供了手动控制。
抠丁客


