Form表单
具有数据收集、校验和提交功能的表单,包含复选框、单选框、输入框、下拉选择框等元素。
该组件需要与 Angular表单 结合使用,开发者根据需要可以自由选择 响应式表单 或 模板驱动表单.
使用该组件前请确保您已经阅读并掌握了 Forms 的使用方式。
表单
我们提供了以下三种排列方式:
- 水平排列:标签和表单控件水平排列;(默认)
- 垂直排列:标签和表单控件上下垂直排列;
- 行内排列:表单项水平行内排列。
表单项 nz-form-item
表单项用于区分表单中不同的区域,包含表单域和表单标签(可选)。
表单标签 nz-form-label
用于标示当前表单项的内容,可选。
表单域 nz-form-control
表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等。
<form nz-form>
<nz-form-item>
<nz-form-label [nzSpan]="6" nzFor="email">E-mail</nz-form-label>
<nz-form-control [nzSpan]="14">
<input nz-input name="email" type="email" id="email">
</nz-form-control>
</nz-form-item >
</form>
import { NzFormModule } from 'ng-zorro-antd/form';
代码演示
内联登录栏
内联登录栏,常用在顶部导航栏中。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'nz-demo-form-horizontal-login',
template: `
<form nz-form [nzLayout]="'inline'" [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-control nzErrorTip="Please input your username!">
<nz-input-group nzPrefixIcon="user">
<input formControlName="userName" nz-input placeholder="Username" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control nzErrorTip="Please input your Password!">
<nz-input-group nzPrefixIcon="lock">
<input formControlName="password" nz-input type="password" placeholder="Password" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control>
<button nz-button nzType="primary" [disabled]="!validateForm.valid">Log in</button>
</nz-form-control>
</nz-form-item>
</form>
`
})
export class NzDemoFormHorizontalLoginComponent implements OnInit {
validateForm: FormGroup;
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
userName: [null, [Validators.required]],
password: [null, [Validators.required]],
remember: [true]
});
}
}
登录框
普通的登录框,可以容纳更多的元素。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'nz-demo-form-normal-login',
template: `
<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-control nzErrorTip="Please input your username!">
<nz-input-group nzPrefixIcon="user">
<input type="text" nz-input formControlName="userName" placeholder="Username" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control nzErrorTip="Please input your Password!">
<nz-input-group nzPrefixIcon="lock">
<input type="password" nz-input formControlName="password" placeholder="Password" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<div nz-row class="login-form-margin">
<div nz-col [nzSpan]="12">
<label nz-checkbox formControlName="remember">
<span>Remember me</span>
</label>
</div>
<div nz-col [nzSpan]="12">
<a class="login-form-forgot">Forgot password</a>
</div>
</div>
<button nz-button class="login-form-button login-form-margin" [nzType]="'primary'">Log in</button>
Or <a> register now! </a>
</form>
`,
styles: [
`
.login-form {
max-width: 300px;
}
.login-form-margin {
margin-bottom: 16px;
}
.login-form-forgot {
float: right;
}
.login-form-button {
width: 100%;
}
`
]
})
export class NzDemoFormNormalLoginComponent implements OnInit {
validateForm: FormGroup;
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
userName: [null, [Validators.required]],
password: [null, [Validators.required]],
remember: [true]
});
}
}
注册新用户
用户填写必须的信息以注册新用户。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'nz-demo-form-register',
template: `
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="email">E-mail</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid E-mail!">
<input nz-input formControlName="email" id="email" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="password" nzRequired>Password</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="Please input your password!">
<input nz-input type="password" id="password" formControlName="password" (ngModelChange)="updateConfirmValidator()" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="checkPassword" nzRequired>Confirm Password</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" [nzErrorTip]="errorTpl">
<input nz-input type="password" formControlName="checkPassword" id="checkPassword" />
<ng-template #errorTpl let-control>
<ng-container *ngIf="control.hasError('required')">
Please confirm your password!
</ng-container>
<ng-container *ngIf="control.hasError('confirm')">
Two passwords that you enter is inconsistent!
</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="nickname" nzRequired>
<span>
Nickname
<i nz-icon nz-tooltip nzTitle="What do you want other to call you" nzType="question-circle" nzTheme="outline"></i>
</span>
</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="Please input your nickname!">
<input nz-input id="nickname" formControlName="nickname" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="phoneNumber" nzRequired>Phone Number</nz-form-label>
<nz-form-control
[nzSm]="14"
[nzXs]="24"
[nzValidateStatus]="validateForm.controls['phoneNumber']"
nzErrorTip="Please input your phone number!"
>
<nz-input-group [nzAddOnBefore]="addOnBeforeTemplate">
<ng-template #addOnBeforeTemplate>
<nz-select formControlName="phoneNumberPrefix" class="phone-select">
<nz-option nzLabel="+86" nzValue="+86"></nz-option>
<nz-option nzLabel="+87" nzValue="+87"></nz-option>
</nz-select>
</ng-template>
<input formControlName="phoneNumber" id="'phoneNumber'" nz-input />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="website" nzRequired>Website</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="Please input website!">
<input nz-input id="website" formControlName="website" placeholder="website" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="captcha" nzRequired>Captcha</nz-form-label>
<nz-form-control
[nzSm]="14"
[nzXs]="24"
nzErrorTip="Please input the captcha you got!"
nzExtra="We must make sure that your are a human."
>
<div nz-row [nzGutter]="8">
<div nz-col [nzSpan]="12">
<input nz-input formControlName="captcha" id="captcha" />
</div>
<div nz-col [nzSpan]="12">
<button nz-button (click)="getCaptcha($event)">Get captcha</button>
</div>
</div>
</nz-form-control>
</nz-form-item>
<nz-form-item nz-row class="register-area">
<nz-form-control [nzSpan]="14" [nzOffset]="6">
<label nz-checkbox formControlName="agree">
<span>I have read the <a>agreement</a></span>
</label>
</nz-form-control>
</nz-form-item>
<nz-form-item nz-row class="register-area">
<nz-form-control [nzSpan]="14" [nzOffset]="6">
<button nz-button nzType="primary">Register</button>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
[nz-form] {
max-width: 600px;
}
.phone-select {
width: 70px;
}
.register-are {
margin-bottom: 8px;
}
`
]
})
export class NzDemoFormRegisterComponent implements OnInit {
validateForm: FormGroup;
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
}
updateConfirmValidator(): void {
/** wait for refresh value */
Promise.resolve().then(() => this.validateForm.controls.checkPassword.updateValueAndValidity());
}
confirmationValidator = (control: FormControl): { [s: string]: boolean } => {
if (!control.value) {
return { required: true };
} else if (control.value !== this.validateForm.controls.password.value) {
return { confirm: true, error: true };
}
return {};
};
getCaptcha(e: MouseEvent): void {
e.preventDefault();
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
email: [null, [Validators.email, Validators.required]],
password: [null, [Validators.required]],
checkPassword: [null, [Validators.required, this.confirmationValidator]],
nickname: [null, [Validators.required]],
phoneNumberPrefix: ['+86'],
phoneNumber: [null, [Validators.required]],
website: [null, [Validators.required]],
captcha: [null, [Validators.required]],
agree: [false]
});
}
}
高级搜索
三列栅格式的表单排列方式,常用于数据表格的高级搜索。
有部分定制的样式代码,由于输入标签长度不确定,需要根据具体情况自行调整。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'nz-demo-form-advanced-search',
template: `
<form nz-form [formGroup]="validateForm" class="ant-advanced-search-form">
<div nz-row [nzGutter]="24">
<div nz-col [nzSpan]="8" *ngFor="let control of controlArray" [hidden]="!control.show">
<nz-form-item nzFlex>
<nz-form-label [nzFor]="'field' + control.index">Field {{ control.index }}</nz-form-label>
<nz-form-control>
<input nz-input placeholder="placeholder" [formControlName]="'field' + control.index" [attr.id]="'field' + control.index" />
</nz-form-control>
</nz-form-item>
</div>
</div>
<div nz-row>
<div nz-col [nzSpan]="24" class="search-area">
<button nz-button [nzType]="'primary'">Search</button>
<button nz-button (click)="resetForm()">Clear</button>
<a class="collapse" (click)="toggleCollapse()">
Collapse
<i nz-icon [nzType]="isCollapse ? 'down' : 'up'"></i>
</a>
</div>
</div>
</form>
<div class="search-result-list">
Search Result List
</div>
`,
styles: [
`
.ant-advanced-search-form {
padding: 24px;
background: #fbfbfb;
border: 1px solid #d9d9d9;
border-radius: 6px;
}
.search-result-list {
margin-top: 16px;
border: 1px dashed #e9e9e9;
border-radius: 6px;
background-color: #fafafa;
min-height: 200px;
text-align: center;
padding-top: 80px;
}
[nz-form-label] {
overflow: visible;
}
button {
margin-left: 8px;
}
.collapse {
margin-left: 8px;
font-size: 12px;
}
.search-area {
text-align: right;
}
`
]
})
export class NzDemoFormAdvancedSearchComponent implements OnInit {
validateForm: FormGroup;
controlArray: Array<{ index: number; show: boolean }> = [];
isCollapse = true;
toggleCollapse(): void {
this.isCollapse = !this.isCollapse;
this.controlArray.forEach((c, index) => {
c.show = this.isCollapse ? index < 6 : true;
});
}
resetForm(): void {
this.validateForm.reset();
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({});
for (let i = 0; i < 10; i++) {
this.controlArray.push({ index: i, show: i < 6 });
this.validateForm.addControl(`field${i}`, new FormControl());
}
}
}
动态增减表单项
动态增加、减少表单项。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'nz-demo-form-dynamic-form-item',
template: `
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item *ngFor="let control of listOfControl; let i = index">
<nz-form-label [nzXs]="24" [nzSm]="4" *ngIf="i == 0" [nzFor]="control.controlInstance">Passengers </nz-form-label>
<nz-form-control
[nzXs]="24"
[nzSm]="20"
[nzOffset]="i == 0 ? 0 : 4"
nzErrorTip="Please input passenger's name or delete this field."
>
<input
class="passenger-input"
nz-input
placeholder="placeholder"
[attr.id]="control.id"
[formControlName]="control.controlInstance"
/>
<i nz-icon nzType="minus-circle-o" class="dynamic-delete-button" (click)="removeField(control, $event)"></i>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzXs]="{ span: 24, offset: 0 }" [nzSm]="{ span: 20, offset: 4 }">
<button nz-button nzType="dashed" class="add-button" (click)="addField($event)">
<i nz-icon nzType="plus"></i>
Add field
</button>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzXs]="{ span: 24, offset: 0 }" [nzSm]="{ span: 20, offset: 4 }">
<button nz-button nzType="primary">Submit</button>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
.dynamic-delete-button {
cursor: pointer;
position: relative;
top: 4px;
font-size: 24px;
color: #999;
transition: all 0.3s;
}
.dynamic-delete-button:hover {
color: #777;
}
.passenger-input {
width: 60%;
margin-right: 8px;
}
[nz-form] {
max-width: 600px;
}
.add-button {
width: 60%;
}
`
]
})
export class NzDemoFormDynamicFormItemComponent implements OnInit {
validateForm: FormGroup;
listOfControl: Array<{ id: number; controlInstance: string }> = [];
addField(e?: MouseEvent): void {
if (e) {
e.preventDefault();
}
const id = this.listOfControl.length > 0 ? this.listOfControl[this.listOfControl.length - 1].id + 1 : 0;
const control = {
id,
controlInstance: `passenger${id}`
};
const index = this.listOfControl.push(control);
console.log(this.listOfControl[this.listOfControl.length - 1]);
this.validateForm.addControl(this.listOfControl[index - 1].controlInstance, new FormControl(null, Validators.required));
}
removeField(i: { id: number; controlInstance: string }, e: MouseEvent): void {
e.preventDefault();
if (this.listOfControl.length > 1) {
const index = this.listOfControl.indexOf(i);
this.listOfControl.splice(index, 1);
console.log(this.listOfControl);
this.validateForm.removeControl(i.controlInstance);
}
}
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
console.log(this.validateForm.value);
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({});
this.addField();
}
}
时间类控件
时间类组件的输入和输出类型均为 Date
类型,可以通过 date-fns 工具库进行进一步的处理。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'nz-demo-form-time-related-controls',
template: `
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSm]="8" [nzXs]="24" nzRequired>DatePicker</nz-form-label>
<nz-form-control [nzSm]="16" [nzXs]="24">
<nz-date-picker formControlName="datePicker"></nz-date-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="8" [nzXs]="24" nzRequired>DatePicker[ShowTime]</nz-form-label>
<nz-form-control [nzSm]="16" [nzXs]="24">
<nz-date-picker nzShowTime formControlName="datePickerTime"></nz-date-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="8" [nzXs]="24" nzRequired>MonthPicker</nz-form-label>
<nz-form-control [nzSm]="16" [nzXs]="24">
<nz-month-picker formControlName="monthPicker"></nz-month-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="8" [nzXs]="24" nzRequired>RangePicker</nz-form-label>
<nz-form-control [nzSm]="16" [nzXs]="24">
<nz-range-picker formControlName="rangePicker"></nz-range-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="8" [nzXs]="24" nzRequired>RangePicker[showTime]</nz-form-label>
<nz-form-control [nzSm]="16" [nzXs]="24">
<nz-range-picker nzShowTime formControlName="rangePickerTime"></nz-range-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="8" [nzXs]="24" nzRequired>TimePicker</nz-form-label>
<nz-form-control [nzSm]="16" [nzXs]="24">
<nz-time-picker formControlName="timePicker"></nz-time-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzXs]="{ span: 24, offset: 0 }" [nzSm]="{ span: 16, offset: 8 }">
<button nz-button nzType="primary">Submit</button>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
form {
max-width: 600px;
}
`
]
})
export class NzDemoFormTimeRelatedControlsComponent implements OnInit {
validateForm: FormGroup;
submitForm(): void {
console.log(this.validateForm.value);
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
datePicker: [null],
datePickerTime: [null],
monthPicker: [null],
rangePicker: [[]],
rangePickerTime: [[]],
timePicker: [null]
});
}
}
响应式表单验证
我们在 nz-form-control
上 提供了 nzValidateStatus``nzHasFeedback
等属性,当使用响应式表单时,可以自己定义校验的时机和内容。
nzValidateStatus
: 校验状态,默认自动从nz-form-control
中的NgControl
获得校验状态,也可以手动指定为特定的NgControl
。nzHasFeedback
:用于给输入框添加反馈图标。nzSuccessTip``nzWarningTip``nzErrorTip``nzValidatingTip
:设置不同状态校验文案。当同一种状态下存在多种提示情况时,
nzSuccessTip``nzWarningTip``nzErrorTip``nzValidatingTip
均支持传入TemplateRef<{ $implicit: FormControl }
类型,可以通过模板变量)导出FormControl
后用于切换不同的提示信息。
当 FormControl.status 为INVALID
并且错误包含{warning:true}
时,nz-form-control
显示警告状态。
import { Component } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms';
import { Observable, Observer } from 'rxjs';
@Component({
selector: 'nz-demo-form-validate-reactive',
template: `
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm(validateForm.value)">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Username</nz-form-label>
<nz-form-control [nzSpan]="12" nzHasFeedback nzValidatingTip="Validating..." [nzErrorTip]="userErrorTpl">
<input nz-input formControlName="userName" placeholder="async validate try to write JasonWood" />
<ng-template #userErrorTpl let-control>
<ng-container *ngIf="control.hasError('required')">
Please input your username!
</ng-container>
<ng-container *ngIf="control.hasError('duplicated')">
The username is redundant!
</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>E-mail</nz-form-label>
<nz-form-control [nzSpan]="12" nzHasFeedback [nzErrorTip]="emailErrorTpl">
<input nz-input formControlName="email" placeholder="email" type="email" />
<ng-template #emailErrorTpl let-control>
<ng-container *ngIf="control.hasError('email')">
The input is not valid E-mail!
</ng-container>
<ng-container *ngIf="control.hasError('required')">
Please input your E-mail!
</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzHasFeedback nzErrorTip="Please input your password!">
<input nz-input type="password" formControlName="password" (ngModelChange)="validateConfirmPassword()" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Confirm Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzHasFeedback [nzErrorTip]="passwordErrorTpl">
<input nz-input type="password" formControlName="confirm" placeholder="confirm your password" />
<ng-template #passwordErrorTpl let-control>
<ng-container *ngIf="control.hasError('required')">
Please confirm your password!
</ng-container>
<ng-container *ngIf="control.hasError('confirm')">
Password is inconsistent!
</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Comment</nz-form-label>
<nz-form-control [nzSpan]="12" nzErrorTip="Please write something here!">
<textarea formControlName="comment" nz-input rows="2" placeholder="write any thing"></textarea>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzOffset]="7" [nzSpan]="12">
<button nz-button nzType="primary" [disabled]="!validateForm.valid">Submit</button>
<button nz-button (click)="resetForm($event)">Reset</button>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
[nz-form] {
max-width: 600px;
}
button {
margin-left: 8px;
}
`
]
})
export class NzDemoFormValidateReactiveComponent {
validateForm: FormGroup;
submitForm(value: { userName: string; email: string; password: string; confirm: string; comment: string }): void {
for (const key in this.validateForm.controls) {
this.validateForm.controls[key].markAsDirty();
this.validateForm.controls[key].updateValueAndValidity();
}
console.log(value);
}
resetForm(e: MouseEvent): void {
e.preventDefault();
this.validateForm.reset();
for (const key in this.validateForm.controls) {
this.validateForm.controls[key].markAsPristine();
this.validateForm.controls[key].updateValueAndValidity();
}
}
validateConfirmPassword(): void {
setTimeout(() => this.validateForm.controls.confirm.updateValueAndValidity());
}
userNameAsyncValidator = (control: FormControl) =>
new Observable((observer: Observer<ValidationErrors | null>) => {
setTimeout(() => {
if (control.value === 'JasonWood') {
// you have to return `{error: true}` to mark it as an error event
observer.next({ error: true, duplicated: true });
} else {
observer.next(null);
}
observer.complete();
}, 1000);
});
confirmValidator = (control: FormControl): { [s: string]: boolean } => {
if (!control.value) {
return { error: true, required: true };
} else if (control.value !== this.validateForm.controls.password.value) {
return { confirm: true, error: true };
}
return {};
};
constructor(private fb: FormBuilder) {
this.validateForm = this.fb.group({
userName: ['', [Validators.required], [this.userNameAsyncValidator]],
email: ['', [Validators.email, Validators.required]],
password: ['', [Validators.required]],
confirm: ['', [this.confirmValidator]],
comment: ['', [Validators.required]]
});
}
}
模板驱动表单验证
当使用模板驱动表单时,模板可以根据模板设定自动进行校验。
nzHasFeedback
:用于给输入框添加反馈图标。nzSuccessTip``nzWarningTip``nzErrorTip``nzValidatingTip
:设置不同状态校验文案。当同一种状态下存在多种提示情况时,
nzSuccessTip``nzWarningTip``nzErrorTip``nzValidatingTip
均支持传入TemplateRef<{ $implicit: NgModel }
类型,可以通过模板变量)导出NgModel
后用于切换不同的提示信息。
import { Component } from '@angular/core';
@Component({
selector: 'nz-demo-form-validate-template',
template: `
<form nz-form>
<nz-form-item>
<nz-form-label [nzSpan]="5">Required</nz-form-label>
<nz-form-control nzHasFeedback [nzSpan]="12" nzErrorTip="Input is required">
<input nz-input [ngModel]="'Required Input'" name="required" required />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">MaxLength</nz-form-label>
<nz-form-control nzHasFeedback [nzSpan]="12" nzErrorTip="MaxLength is 6">
<input nz-input [ngModel]="'MaxLength is 6'" name="maxlength" maxlength="6" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">MinLength</nz-form-label>
<nz-form-control nzHasFeedback [nzSpan]="12" nzErrorTip="MinLength is 6">
<input nz-input [ngModel]="'MinLength is 6'" name="minlength" minlength="6" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Email</nz-form-label>
<nz-form-control nzHasFeedback [nzSpan]="12" nzErrorTip="Email is not valid">
<input nz-input [ngModel]="'Input Email'" name="email" email />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Pattern</nz-form-label>
<nz-form-control nzHasFeedback [nzSpan]="12" nzErrorTip="Pattern not match">
<input nz-input [ngModel]="'Match pattern'" name="pattern" pattern=".{3,}" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Mix</nz-form-label>
<nz-form-control nzHasFeedback [nzSpan]="12" [nzErrorTip]="combineTpl">
<input nz-input [ngModel]="'MaxLength is 12 and MinLength is 6'" name="mix" minlength="6" maxlength="12" required />
<ng-template #combineTpl let-control>
<ng-container *ngIf="control.hasError('maxlength')">MaxLength is 12</ng-container>
<ng-container *ngIf="control.hasError('minlength')">MinLength is 6</ng-container>
<ng-container *ngIf="control.hasError('required')">Input is required</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
[nz-form] {
max-width: 600px;
}
`
]
})
export class NzDemoFormValidateTemplateComponent {}
自动提示
让提示变得更简单。
需要预先自定义 Validators
和提供 nzAutoTips
,它们优先级如下:
Validators
>nzAutoTips
- 通过
@Input
设置nzAutoTips
- 通过全局配置设置
nzAutoTips
另外,你可以使用 nzDisableAutoTips
去禁用它。
import { Component } from '@angular/core';
import { AbstractControl, FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { Observable, Observer } from 'rxjs';
@Component({
selector: 'nz-demo-form-auto-tips',
template: `
<form nz-form [nzAutoTips]="autoTips" [formGroup]="validateForm" (ngSubmit)="submitForm(validateForm.value)">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Username</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidatingTip="Validating...">
<input nz-input formControlName="userName" placeholder="async validate try to write JasonWood" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Mobile</nz-form-label>
<nz-form-control [nzSpan]="12">
<input nz-input formControlName="mobile" placeholder="mobile" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>E-mail</nz-form-label>
<nz-form-control [nzSpan]="12">
<input nz-input formControlName="email" placeholder="email" type="email" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzDisableAutoTips nzErrorTip="Please input your password!">
<input nz-input type="password" formControlName="password" (ngModelChange)="validateConfirmPassword()" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Confirm Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzDisableAutoTips [nzErrorTip]="passwordErrorTpl">
<input nz-input type="password" formControlName="confirm" placeholder="confirm your password" />
<ng-template #passwordErrorTpl let-control>
<ng-container *ngIf="control.hasError('required')">
Please confirm your password!
</ng-container>
<ng-container *ngIf="control.hasError('confirm')">
Password is inconsistent!
</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzOffset]="7" [nzSpan]="12">
<button nz-button nzType="primary">Submit</button>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
[nz-form] {
max-width: 600px;
}
`
]
})
export class NzDemoFormAutoTipsComponent {
validateForm: FormGroup;
// current locale is key of the nzAutoTips
autoTips: Record<string, Record<string, string>> = {
'zh-cn': {
required: '必填项',
email: '邮箱格式不正确'
},
en: {
required: 'Input is required',
email: 'The input is not valid email'
}
};
submitForm(value: { userName: string; email: string; password: string; confirm: string; comment: string }): void {
for (const key in this.validateForm.controls) {
this.validateForm.controls[key].markAsDirty();
this.validateForm.controls[key].updateValueAndValidity();
}
console.log(value);
}
validateConfirmPassword(): void {
setTimeout(() => this.validateForm.controls.confirm.updateValueAndValidity());
}
userNameAsyncValidator = (control: FormControl) =>
new Observable((observer: Observer<MyValidationErrors | null>) => {
setTimeout(() => {
if (control.value === 'JasonWood') {
observer.next({
duplicated: { 'zh-cn': `用户名已存在`, en: `The username is redundant!` }
});
} else {
observer.next(null);
}
observer.complete();
}, 1000);
});
confirmValidator = (control: FormControl): { [s: string]: boolean } => {
if (!control.value) {
return { error: true, required: true };
} else if (control.value !== this.validateForm.controls.password.value) {
return { confirm: true, error: true };
}
return {};
};
constructor(private fb: FormBuilder) {
// use `MyValidators`
const { required, maxLength, minLength, email, mobile } = MyValidators;
this.validateForm = this.fb.group({
userName: ['', [required, maxLength(12), minLength(6)], [this.userNameAsyncValidator]],
mobile: ['', [required, mobile]],
email: ['', [required, email]],
password: ['', [required]],
confirm: ['', [this.confirmValidator]]
});
}
}
// current locale is key of the MyErrorsOptions
export type MyErrorsOptions = { 'zh-cn': string; en: string } & Record<string, NzSafeAny>;
export type MyValidationErrors = Record<string, MyErrorsOptions>;
export class MyValidators extends Validators {
static minLength(minLength: number): ValidatorFn {
return (control: AbstractControl): MyValidationErrors | null => {
if (Validators.minLength(minLength)(control) === null) {
return null;
}
return { minlength: { 'zh-cn': `最小长度为 ${minLength}`, en: `MinLength is ${minLength}` } };
};
}
static maxLength(maxLength: number): ValidatorFn {
return (control: AbstractControl): MyValidationErrors | null => {
if (Validators.maxLength(maxLength)(control) === null) {
return null;
}
return { maxlength: { 'zh-cn': `最大长度为 ${maxLength}`, en: `MaxLength is ${maxLength}` } };
};
}
static mobile(control: AbstractControl): MyValidationErrors | null {
const value = control.value;
if (isEmptyInputValue(value)) {
return null;
}
return isMobile(value) ? null : { mobile: { 'zh-cn': `手机号码格式不正确`, en: `Mobile phone number is not valid` } };
}
}
function isEmptyInputValue(value: NzSafeAny): boolean {
return value == null || value.length === 0;
}
function isMobile(value: string): boolean {
return typeof value === 'string' && /(^1\d{10}$)/.test(value);
}
手动指定表单状态
用户可以在通过 nz-form-control
的 nzValidateStatus
属性直接设定表单的状态。
nzValidateStatus
: 校验状态,可选 ‘success’, ‘warning’, ‘error’, ‘validating’。nzHasFeedback
:用于给输入框添加反馈图标。nzSuccessTip``nzWarningTip``nzErrorTip``nzValidatingTip
:设置不同状态校验文案。
import { Component } from '@angular/core';
@Component({
selector: 'nz-demo-form-validate-static',
template: `
<form nz-form>
<nz-form-item>
<nz-form-label [nzSpan]="5">Fail</nz-form-label>
<nz-form-control nzValidateStatus="error" [nzSpan]="12" nzErrorTip="Should be combination of numbers & alphabets">
<input nz-input [ngModel]="'unavailable choice'" name="errorValid" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Warning</nz-form-label>
<nz-form-control nzValidateStatus="warning" [nzSpan]="12">
<input nz-input [ngModel]="'Warning'" name="warningValid" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Validating</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="validating" nzHasFeedback nzValidatingTip="I'm validating the content">
<input nz-input [ngModel]="'The content is being validated'" name="validating" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Success</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="success" nzHasFeedback>
<input nz-input [ngModel]="'The content'" name="successValid" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Warning</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="warning" nzHasFeedback nzWarningTip="Should be combination of numbers & alphabets">
<input nz-input [ngModel]="'Warning'" name="warningHighValid" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Fail</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="error" nzHasFeedback nzErrorTip="Should be combination of numbers & alphabets">
<input nz-input [ngModel]="'unavailable choice'" name="invalidValid" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Success</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="success" nzHasFeedback>
<nz-date-picker name="date-picker-success"></nz-date-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Warning</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="warning" nzHasFeedback>
<nz-time-picker name="time-picker-warning"></nz-time-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Error</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="error" nzHasFeedback>
<nz-select name="select-error" [ngModel]="'Option 1'">
<nz-option nzValue="Option 1" nzLabel="Option 1"></nz-option>
<nz-option nzValue="Option 2" nzLabel="Option 2"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Validating</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="validating" nzHasFeedback>
<nz-select name="select-validate" [ngModel]="'Option 2'">
<nz-option nzValue="Option 1" nzLabel="Option 1"></nz-option>
<nz-option nzValue="Option 2" nzLabel="Option 2"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5">Success</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidateStatus="success" nzHasFeedback>
<nz-input-number name="inputnumber-success" style="width:100%"></nz-input-number>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
[nz-form] {
max-width: 600px;
}
nz-date-picker ::ng-deep .ant-calendar-picker {
width: 100%;
}
nz-date-picker,
nz-time-picker {
width: 100%;
}
`
]
})
export class NzDemoFormValidateStaticComponent {}
表单联动
使用 setValue
来动态设置其他控件的值。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'nz-demo-form-coordinated',
template: `
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSpan]="5" nzRequired nzFor="note">Note</nz-form-label>
<nz-form-control [nzSpan]="12" nzErrorTip="Please input your username!">
<input id="note" type="text" nz-input formControlName="note" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5" nzFor="gender" nzRequired>Gender</nz-form-label>
<nz-form-control [nzSpan]="12" nzErrorTip="Please select your gender!">
<nz-select
id="gender"
formControlName="gender"
nzPlaceHolder="Select a option and change input text above"
(ngModelChange)="genderChange($event)"
>
<nz-option nzValue="male" nzLabel="male"></nz-option>
<nz-option nzValue="female" nzLabel="female"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="12" [nzOffset]="5">
<button nz-button nzType="primary">Submit</button>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
[nz-form] {
max-width: 600px;
}
`
]
})
export class NzDemoFormCoordinatedComponent implements OnInit {
validateForm: FormGroup;
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
}
genderChange(value: string): void {
this.validateForm.get('note')!.setValue(value === 'male' ? 'Hi, man!' : 'Hi, lady!');
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
note: [null, [Validators.required]],
gender: [null, [Validators.required]]
});
}
}
表单布局
表单有三种布局。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'nz-demo-form-layout',
template: `
<form nz-form [nzLayout]="validateForm.get('formLayout')?.value" [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSpan]="isHorizontal ? 4 : null">Form Layout</nz-form-label>
<nz-form-control [nzSpan]="isHorizontal ? 14 : null">
<nz-radio-group formControlName="formLayout">
<label nz-radio-button [nzValue]="'horizontal'">Horizontal</label>
<label nz-radio-button [nzValue]="'vertical'">Vertical</label>
<label nz-radio-button [nzValue]="'inline'">Inline</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="isHorizontal ? 4 : null">Field A</nz-form-label>
<nz-form-control [nzSpan]="isHorizontal ? 14 : null" nzErrorTip="Please input your username!">
<input nz-input formControlName="fieldA" placeholder="input placeholder" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="isHorizontal ? 4 : null">Field B</nz-form-label>
<nz-form-control [nzSpan]="isHorizontal ? 14 : null" nzErrorTip="Please input your Password!">
<input nz-input formControlName="filedB" placeholder="input placeholder" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="isHorizontal ? 14 : null" [nzOffset]="isHorizontal ? 4 : null">
<button nz-button nzType="primary">Submit</button>
</nz-form-control>
</nz-form-item>
</form>
`,
styles: [
`
[nz-form]:not(.ant-form-inline):not(.ant-form-vertical) {
max-width: 600px;
}
`
]
})
export class NzDemoFormLayoutComponent implements OnInit {
validateForm: FormGroup;
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
}
get isHorizontal(): boolean {
return this.validateForm.controls.formLayout?.value === 'horizontal';
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
formLayout: ['horizontal'],
fieldA: [null, [Validators.required]],
filedB: [null, [Validators.required]]
});
}
}
动态校验规则
根据不同情况执行不同的校验规则。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'nz-demo-form-dynamic-rule',
template: `
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSpan]="4" nzRequired nzFor="name">Name</nz-form-label>
<nz-form-control [nzSpan]="8" nzErrorTip="Please input your name">
<input type="text" nz-input formControlName="name" placeholder="Please input your name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="4" nzFor="nickname" [nzRequired]="validateForm.get('required')?.value">Nickname</nz-form-label>
<nz-form-control [nzSpan]="8" nzErrorTip="Please input your nickname">
<input type="text" nz-input formControlName="nickname" placeholder="Please input your nickname" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="8" [nzOffset]="4">
<label nz-checkbox formControlName="required" (ngModelChange)="requiredChange($event)">Nickname is required</label>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="8" [nzOffset]="4">
<button nz-button nzType="primary">Check</button>
</nz-form-control>
</nz-form-item>
</form>
`
})
export class NzDemoFormDynamicRuleComponent implements OnInit {
validateForm: FormGroup;
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
}
requiredChange(required: boolean): void {
if (!required) {
this.validateForm.get('nickname')!.clearValidators();
this.validateForm.get('nickname')!.markAsPristine();
} else {
this.validateForm.get('nickname')!.setValidators(Validators.required);
this.validateForm.get('nickname')!.markAsDirty();
}
this.validateForm.get('nickname')!.updateValueAndValidity();
}
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
name: [null, [Validators.required]],
nickname: [null],
required: [false]
});
}
}
API
[nz-form]directive
参数 | 说明 | 类型 | 默认值 | 全局配置 |
---|---|---|---|---|
[nzLayout] | 表单布局 | ‘horizontal’ | ‘vertical’ | ‘inline’ | ‘horizontal’ | |
[nzNoColon] | 配置 nz-form-label 的 [nzNoColon] 的默认值 | boolean | false | ✅ |
[nzAutoTips] | 配置 nz-form-control 的 [nzAutoTips] 的默认值, 具体用法请参考示例:自动提示 | Record<string, Record<string, string>> | {} | ✅ |
[nzDisableAutoTips] | 配置 nz-form-control 的 [nzDisableAutoTips] 的默认值 | boolean | false | ✅ |
nz-form-itemcomponent
表单项用于区分表单中不同的区域,包含表单域和表单标签(可选)。
所有 nz-row 的参数在
nz-form-item
上均可直接使用。
nz-form-labelcomponent
用于标示当前表单项的内容,可选。
所有 nz-col 的参数在
nz-form-label
上均可直接使用。
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
[nzRequired] | 当前项是否为必填,仅影响样式 | boolean | false |
[nzNoColon] | 是否不显示 label 后面的冒号 | boolean | false |
[nzFor] | label 标签的 for 属性 | string | - |
nz-form-controlcomponent
注意:由于 Angular Form 目前提供的状态变更订阅不完整。手动更改表单状态时,例如
markAsDirty
后,需要执行updateValueAndValidity
通知nz-form-control
进行状态变更。
表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等。
所有 nz-col 的参数在
nz-form-control
上均可直接使用。
参数 | 说明 | 类型 | 默认值 | |
---|---|---|---|---|
[nzValidateStatus] | 会根据传入的 FormControl 或 NgModel 自动生成校验状态,也可以直接指定状态,不传入时默认值为 nz-form-control 中包裹的第一个 FormControl 或 NgModel | ‘success’ | ‘warning’ | ‘error’ | ‘validating’ | FormControl | NgModel | nz-form-control 中包裹的第一个 FormControl 或 NgModel | |
[nzHasFeedback] | 配合 nzValidateStatus 属性使用,展示校验状态图标 | boolean | false | |
[nzExtra] | 用于显示表单额外提示信息 | string | TemplateRef<void> | - | |
[nzSuccessTip] | 校验状态 success 时提示信息 | string | TemplateRef<{ $implicit: FormControl | NgModel }> | - | |
[nzWarningTip] | 校验状态 warning 时提示信息 | string | TemplateRef<{ $implicit: FormControl | NgModel }> | - | |
[nzErrorTip] | 校验状态 error 时提示信息 | string | TemplateRef<{ $implicit: FormControl | NgModel }> | - | |
[nzValidatingTip] | 正在校验时提示信息 | string | TemplateRef<{ $implicit: FormControl | NgModel }> | - | |
[nzAutoTips] | 配置提示的对象, 具体用法请参考示例:自动提示 | Record<string, Record<string, string>> | - | - |
[nzDisableAutoTips] | 禁用自动提示 | boolean | - | - |
nz-form-splitcomponent
用于显示分隔符 -
nz-form-textcomponent
在 nz-form-control
中直接显示文本