跳到主要内容

表单

ReactiveFormsModule

前文提醒

ReactiveFormsModule 是 Angular 提供的模块,用于创建和管理响应式表单(Reactive Forms),让我们可以在组件类中直接控制和更新表单的值和验证状态。使用 ReactiveFormsModule 的动态表单可以根据业务需求动态添加或移除表单控件。

1. 准备工作

首先,确保 ReactiveFormsModule 已导入到你的 Angular 模块中。

步骤 1:在模块中导入 ReactiveFormsModule

在你的模块文件 app.module.ts 中添加 ReactiveFormsModule,确保你的组件可以使用响应式表单功能。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule // 导入 ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

2. 创建动态表单组件

我们将创建一个简单的动态表单组件,它允许用户动态添加和移除表单控件。

步骤 2:创建组件

使用 Angular CLI 创建一个新的组件,命令如下:

ng generate component dynamic-form

步骤 3:实现动态表单逻辑

在生成的组件文件中,使用 FormBuilderFormArray 创建动态表单。

  1. FormBuilder:用于简化表单创建过程。
  2. FormArray:用来管理一个数组形式的表单控件,适用于动态表单。

dynamic-form.component.ts 中:

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';

@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
styleUrls: ['./dynamic-form.component.css']
})
export class DynamicFormComponent {
myForm: FormGroup;

constructor(private fb: FormBuilder) {
// 初始化表单并创建空的 FormArray
this.myForm = this.fb.group({
items: this.fb.array([]) // items 是一个 FormArray
});
}

// 获取 items 数组
get items(): FormArray {
return this.myForm.get('items') as FormArray;
}

// 动态添加新控件
addItem(): void {
const itemForm = this.fb.group({
name: ['', Validators.required], // 名称控件
quantity: [1, [Validators.required, Validators.min(1)]] // 数量控件,最小值为 1
});
this.items.push(itemForm); // 添加到 FormArray 中
}

// 动态移除控件
removeItem(index: number): void {
this.items.removeAt(index); // 从 FormArray 中移除控件
}

// 提交表单
onSubmit(): void {
if (this.myForm.valid) {
console.log('Form submitted:', this.myForm.value);
}
}
}

3. 创建动态表单的 HTML 模板

dynamic-form.component.html 中:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<div formArrayName="items">
<div *ngFor="let item of items.controls; let i = index" [formGroupName]="i" style="margin-bottom: 1em;">
<label>
Name:
<input formControlName="name" placeholder="Item name">
</label>

<label>
Quantity:
<input type="number" formControlName="quantity" placeholder="Quantity">
</label>

<button type="button" (click)="removeItem(i)">Remove</button>
</div>
</div>

<button type="button" (click)="addItem()">Add Item</button>
<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>

4. 运行代码并测试

测试步骤:

  1. 打开 Angular 应用程序,并导航到动态表单组件所在的路由。
  2. 点击 "Add Item" 按钮,会添加新的输入框供用户输入物品的名称和数量。
  3. 填写表单内容,然后点击 "Submit" 提交表单。
  4. 查看控制台,表单的值会打印出来。

总结

  • FormArray 允许我们创建一个可动态增加或删除的控件数组,非常适合动态表单。
  • FormBuilder 使得表单的创建更简洁。
  • Validators 用于设置表单控件的验证条件,确保用户输入符合要求。

FormGroup

在 Angular 中,FormGroup 是用于将多个表单控件组合成一个组的类,便于管理和验证这些控件。一个 FormGroup 可以包含多个 FormControl,并将它们作为一个整体处理,非常适合复杂的表单结构。

下面是关于如何使用 FormGroup 创建一个表单的详细代码和步骤。

1. 准备工作

确保在 Angular 项目中已经导入了 ReactiveFormsModule,以便使用响应式表单的功能。

app.module.ts 中导入 ReactiveFormsModule

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule // 导入 ReactiveFormsModule 以支持响应式表单
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

2. 创建表单组件

创建一个新组件以便实现表单功能。假设我们创建一个注册表单组件,包含“用户名”、“密码”和“电子邮箱”字段。

使用 Angular CLI 创建新组件

ng generate component registration-form

3. 在组件中创建 FormGroup

registration-form.component.ts 中,使用 FormGroupFormControl 创建表单,并在构造函数中初始化这些控件。

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
selector: 'app-registration-form',
templateUrl: './registration-form.component.html',
styleUrls: ['./registration-form.component.css']
})
export class RegistrationFormComponent implements OnInit {
registrationForm: FormGroup;

constructor() {
// 初始化 FormGroup 并定义各个表单控件
this.registrationForm = new FormGroup({
username: new FormControl('', [Validators.required, Validators.minLength(3)]), // 用户名控件,必填,至少 3 个字符
password: new FormControl('', [Validators.required, Validators.minLength(6)]), // 密码控件,必填,至少 6 个字符
email: new FormControl('', [Validators.required, Validators.email]) // 邮箱控件,必填,需符合邮箱格式
});
}

ngOnInit(): void {}

onSubmit(): void {
if (this.registrationForm.valid) {
// 处理有效表单数据
console.log('Form submitted:', this.registrationForm.value);
} else {
// 表单无效时提示错误
console.log('Form is invalid');
}
}
}

4. 创建表单的 HTML 模板

在组件的模板文件 registration-form.component.html 中,使用 Angular 的 formGroup 指令将表单与 registrationForm 绑定,并为每个控件添加输入框。

<form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
<div>
<label for="username">Username:</label>
<input id="username" formControlName="username">
<div *ngIf="registrationForm.get('username')?.invalid && registrationForm.get('username')?.touched">
<small *ngIf="registrationForm.get('username')?.errors?.['required']">Username is required.</small>
<small *ngIf="registrationForm.get('username')?.errors?.['minlength']">Username must be at least 3 characters long.</small>
</div>
</div>

<div>
<label for="password">Password:</label>
<input type="password" id="password" formControlName="password">
<div *ngIf="registrationForm.get('password')?.invalid && registrationForm.get('password')?.touched">
<small *ngIf="registrationForm.get('password')?.errors?.['required']">Password is required.</small>
<small *ngIf="registrationForm.get('password')?.errors?.['minlength']">Password must be at least 6 characters long.</small>
</div>
</div>

<div>
<label for="email">Email:</label>
<input id="email" formControlName="email">
<div *ngIf="registrationForm.get('email')?.invalid && registrationForm.get('email')?.touched">
<small *ngIf="registrationForm.get('email')?.errors?.['required']">Email is required.</small>
<small *ngIf="registrationForm.get('email')?.errors?.['email']">Please enter a valid email address.</small>
</div>
</div>

<button type="submit" [disabled]="registrationForm.invalid">Register</button>
</form>

5. 验证和提交表单

在模板中,每个输入框都有验证提示消息,只有在控件被触摸并且验证未通过时才显示相应的错误提示。用户填写完毕并通过验证后,可以提交表单。表单数据会在控制台打印输出。

总结

  • FormGroup: 用于将多个 FormControl 组合成一个组,便于统一管理和验证。
  • FormControl: 代表单个表单控件,用来接收用户输入的值。
  • Validators: 提供了一些常用的验证器,如 requiredminLengthemail 等。

最终代码

registration-form.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
selector: 'app-registration-form',
templateUrl: './registration-form.component.html',
styleUrls: ['./registration-form.component.css']
})
export class RegistrationFormComponent implements OnInit {
registrationForm: FormGroup;

constructor() {
this.registrationForm = new FormGroup({
username: new FormControl('', [Validators.required, Validators.minLength(3)]),
password: new FormControl('', [Validators.required, Validators.minLength(6)]),
email: new FormControl('', [Validators.required, Validators.email])
});
}

ngOnInit(): void {}

onSubmit(): void {
if (this.registrationForm.valid) {
console.log('Form submitted:', this.registrationForm.value);
} else {
console.log('Form is invalid');
}
}
}

registration-form.component.html

<form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
<div>
<label for="username">Username:</label>
<input id="username" formControlName="username">
<div *ngIf="registrationForm.get('username')?.invalid && registrationForm.get('username')?.touched">
<small *ngIf="registrationForm.get('username')?.errors?.['required']">Username is required.</small>
<small *ngIf="registrationForm.get('username')?.errors?.['minlength']">Username must be at least 3 characters long.</small>
</div>
</div>

<div>
<label for="password">Password:</label>
<input type="password" id="password" formControlName="password">
<div *ngIf="registrationForm.get('password')?.invalid && registrationForm.get('password')?.touched">
<small *ngIf="registrationForm.get('password')?.errors?.['required']">Password is required.</small>
<small *ngIf="registrationForm.get('password')?.errors?.['minlength']">Password must be at least 6 characters long.</small>
</div>
</div>

<div>
<label for="email">Email:</label>
<input id="email" formControlName="email">
<div *ngIf="registrationForm.get('email')?.invalid && registrationForm.get('email')?.touched">
<small *ngIf="registrationForm.get('email')?.errors?.['required']">Email is required.</small>
<small *ngIf="registrationForm.get('email')?.errors?.['email']">Please enter a valid email address.</small>
</div>
</div>

<button type="submit" [disabled]="registrationForm.invalid">Register</button>
</form>

表单处理

在 Angular 中,是构建交互式用户界面的重要部分。为了有效地管理和验证用户输入,Angular 提供了 FormBuilderValidators 这两个工具。下面是对它们的详细解释。

1. FormBuilder

FormBuilder 是 Angular 中的一个服务,用于简化创建表单控件的过程。它使得表单的创建更加简洁和直观。FormBuilder 提供了一些方法,可以用来生成表单控件、表单组和表单数组。

功能和使用

  • 创建表单控件: 使用 FormBuilder 可以方便地创建表单控件和组。
  • 更好的可读性: 通过使用 FormBuilder,表单的结构可以更加清晰,代码更易于理解和维护。

示例代码

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
selector: 'app-my-form',
templateUrl: './my-form.component.html',
})
export class MyFormComponent implements OnInit {
myForm: FormGroup;

constructor(private fb: FormBuilder) { } // 注入 FormBuilder

ngOnInit(): void {
// 使用 FormBuilder 创建表单
this.myForm = this.fb.group({
username: ['', Validators.required], // 创建控件并添加验证器
password: ['', [Validators.required, Validators.minLength(6)]]
});
}

onSubmit(): void {
if (this.myForm.valid) {
// 处理有效表单
console.log(this.myForm.value);
} else {
// 处理无效表单
console.log('Form is invalid');
}
}
}

2. Validators

Validators 是一个提供常用表单验证器的工具类。它提供了一系列静态方法,可以用于检查表单控件的输入值是否符合特定规则。

功能和使用

  • 常用验证器: Validators 提供了一些常用的验证器,如 requiredminLengthmaxLengthpattern 等。
  • 自定义验证器: 除了使用内置的验证器,开发者还可以定义自定义验证器,以满足特定的业务需求。

示例代码

import { AbstractControl, ValidationErrors } from '@angular/forms';

// 自定义验证器示例
export function customValidator(control: AbstractControl): ValidationErrors | null {
const forbidden = /admin/.test(control.value); // 检查输入值是否包含 "admin"
return forbidden ? { forbiddenName: { value: control.value } } : null; // 返回验证结果
}

3. 综合示例

以下是一个包含自定义验证器、FormBuilderValidators 的完整示例:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { customValidator } from './custom-validator'; // 导入自定义验证器

@Component({
selector: 'app-registration-form',
templateUrl: './registration-form.component.html',
})
export class RegistrationFormComponent implements OnInit {
registrationForm: FormGroup;

constructor(private fb: FormBuilder) { }

ngOnInit(): void {
this.registrationForm = this.fb.group({
username: ['', [Validators.required, customValidator]], // 使用自定义验证器
password: ['', [Validators.required, Validators.minLength(6)]],
email: ['', [Validators.required, Validators.email]] // 使用内置的 email 验证器
});
}

onSubmit(): void {
if (this.registrationForm.valid) {
console.log(this.registrationForm.value);
} else {
console.log('Form is invalid');
}
}
}

总结

  • FormBuilder: 用于简化表单控件的创建,使表单结构更加清晰,易于维护。
  • Validators: 提供内置的常用验证器,同时支持自定义验证器,帮助开发者有效地验证用户输入。
  • 自定义验证器: 通过自定义验证器,开发者可以根据业务需求扩展验证逻辑,增强表单的灵活性和适用性。

通过结合使用 FormBuilderValidators,Angular 提供了强大且灵活的方式来处理表单输入和验证,确保用户数据的有效性。

自定义的验证方法

FormBuilder 是一个 Angular 提供的用于简化表单组件中创建表单控件的辅助工具类。

Validators 是一个提供常用验证器的工具类,用于在表单控件中执行验证。

import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms'

constructor(private fb: FormBuilder) { }

valiDataForm: FormGroup = this.fb.group({
userName: [
'',
[Validators.required, Validators.maxLength(18), Validators.minLength(6)],
],
password: ['', [this.passwordVal]],
phone: ['', [Validators.required, this.phoneVal]],
});

passwordVal(password: FormControl): object {
const value = password.value || '';
if (!value) {
return { msg: '请输入密码' };
} else {
const valid = value.match(/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/);
return valid ? {} : { msg: '密码至少包含6位数字或英文,长度6-20' };
}
}

phoneVal(phone: FormControl): object {
const value = phone.value || '';
if (!value) return { msg: '请输入手机号' };
const valid = value.match(/[0-9]{11}/);
return valid ? {} : { msg: '联系电话必须是11位数字' };
}

subFormFunction() {
console.log(this.valiDataForm.get('userName')?.value);
console.log(this.valiDataForm.get('password')?.value);
console.log(this.valiDataForm.get('phone')?.value);
}

前端

<form [formGroup]="valiDataForm">

<label>
账号: <input type="text" formControlName="userName" />
</label>

<p *ngIf="valiDataForm.get('userName')?.errors?.['required']">请输入账号</p>
<p *ngIf="valiDataForm.get('userName')?.errors?.['minlength']?.requiredLength
||valiDataForm.get('userName')?.errors?.['maxlength']?.requiredLength">账号长度在6-18位之间</p>

<br />

<label>
密码: <input type="text" formControlName="password" />
</label>

<p *ngIf="valiDataForm.get('password')?.errors?.['msg']">{{ valiDataForm.get('password')?.errors?.['msg'] }}</p>

<br />

<label>
手机号: <input type="text" formControlName="phone" />
</label>

<p *ngIf="valiDataForm.get('phone')?.errors?.['msg']">{{ valiDataForm.get('phone')?.errors?.['msg'] }}</p>


<br />

<button (click)="subFormFunction()">
提交
</button>
</form>