介绍
Angular 提供了两种处理表单的方式: 模板驱动表单 和 反应式表单(也称为 模型驱动表单)。 模板驱动的表单是在 Angular 中使用表单的默认方式。 对于模板驱动的表单,模板指令用于构建表单的内部表示。 使用响应式表单,您可以在组件类中构建自己的表单表示。
注意: Angular 2 引入了响应式表单。
以下是反应形式的一些优点:
- 使用 自定义验证器
- 动态更改验证
- 动态添加表单域
在本文中,您将探索如何将响应式表单应用于示例 Angular 应用程序。
先决条件
如果您想继续阅读本文,您将需要:
- Node.js 安装在本地,您可以按照【X57X】如何安装Node.js 并创建本地开发环境【X126X】进行。
这篇文章假设你对 Angular 有一些基本的了解。
这篇文章还假设您是从 @angular/cli
生成的新 Angular 项目构建的。 如果您开始使用 Angular CLI,可以 参考这篇文章 。
本教程已使用 Node v15.1.0、npm
v6.14.8、@angular/core
v11.0.0 和 @angular/forms
v11.0.0 进行了验证。
第 1 步 — 设置项目
就本教程而言,您将从使用 @angular/cli
生成的默认 Angular 项目构建。
npx @angular/cli new angular-reactive-forms-example --style=css --routing=false --skip-tests
这将配置一个新的 Angular 项目,其样式设置为“CSS”(与“Sass”、“Less”或“Stylus”相对)、无路由和跳过测试。
导航到新创建的项目目录:
cd angular-reactive-forms-example
要使用响应式表单,您将使用 ReactiveFormsModule
而不是 FormsModule
。
在代码编辑器中打开 app.module.ts
并添加 ReactiveFormsModule
:
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, ReactiveFormsModule, ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
此时,您应该有一个带有 ReactiveFormsModule
的新 Angular 项目。
第 2 步 — 向组件模板添加表单
使用响应式表单,逻辑完全在组件类中声明。
在代码编辑器中打开 app.component.html
并添加以下代码行:
src/app/app.component.html
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)"> <div> <label> Name: <input formControlName="name" placeholder="Your name"> </label> </div> <div> <label> Email: <input formControlName="email" placeholder="Your email"> </label> </div> <div> <label> Message: <input formControlName="message" placeholder="Your message"> </label> </div> <button type="submit">Send</button> </form>
此代码将创建一个包含三个字段的表单:name
、email
和 message
。 还有一个带有标签 "Send"
的 "submit"
按钮。 提交表单时,会调用方法onSubmit(myForm)
。
注意: 如果你使用 Angular 2.x,你还应该添加带有 form
标签的 novalidate
指令,因为 Angular 会覆盖 HTML5 的验证。 使用 Angular 4+,novalidate
会自动添加到幕后。
让我们分解一下:
formGroup
:表单将在组件类中被视为FormGroup
,因此formGroup
指令允许为表单组命名。ngSubmit
:这是提交表单时触发的事件。formControlName
:每个表单域都应该有一个formControlName
指令,其值将是组件类中使用的名称。
此时,您应该有一个新的 Angular 项目,其中包含使用表单的组件模板。
第三步——构建组件类
接下来,在组件类中,您将在 FormGroup
中定义 FormGroup
和各个 FormControl
。
如果在 newing a FormControl
时提供了一个值,它将用作该字段的初始值。
注意 FormGroup
和 FormControl
名称与模板中使用的相同。 还要注意如何在 ngOnInit
生命周期钩子 中初始化 FormGroup
:
src/app/app.component.ts
import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { myForm: FormGroup; ngOnInit() { this.myForm = new FormGroup({ name: new FormControl('Sammy'), email: new FormControl(''), message: new FormControl('') }); } onSubmit(form: FormGroup) { console.log('Valid?', form.valid); // true or false console.log('Name', form.value.name); console.log('Email', form.value.email); console.log('Message', form.value.message); } }
就本教程而言,onSubmit
方法实际上并不将提交的表单值传递给任何外部服务或服务器。 它用于显示如何访问表单的有效性和 FormControl
值。
此时,您可以编译您的应用程序并在 Web 浏览器中打开它。 输入 name
、email
和 message
的值并按 Submit 后,控制台日志将显示这些值。
第 4 步 — 更新组件类以使用 FormBuilder
ngOnInit
表单结构可以用 FormBuilder
助手重写。 这允许您放弃表单组和表单控件的所有 newing。
在代码编辑器中重新访问 app.component.ts
并删除 FormControl
并将 FormGroup
替换为 FormBuilder
:
src/app/app.component.ts
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { myForm: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit() { this.myForm = this.fb.group({ name: 'Sammy', email: '', message: '' }); } onSubmit(form: FormGroup) { console.log('Valid?', form.valid); // true or false console.log('Name', form.value.name); console.log('Email', form.value.email); console.log('Message', form.value.message); } }
此带有 FormBuilder
的代码减少了用于创建 FormGroup
的样板代码量。
第 5 步 — 更新组件类以使用 Validators
将 Validators
类添加到您的导入中,并使用数组而不是简单的字符串值来声明您的表单控件。
数组中的第一个值是初始表单值,第二个值是供验证器使用的。 请注意如何通过将多个验证器包装到一个数组中来在同一个表单控件上使用它们。
RevisitRevisit app.component.ts
在代码编辑器中添加 Validators
:
src/app/app.component.ts
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { myForm: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit() { this.myForm = this.fb.group({ name: ['Sammy', Validators.required], email: ['', [Validators.required, Validators.email]], message: ['', [Validators.required, Validators.minLength(15)]], }); } onSubmit(form: FormGroup) { console.log('Valid?', form.valid); // true or false console.log('Name', form.value.name); console.log('Email', form.value.email); console.log('Message', form.value.message); } }
此代码将 required
添加到 name
、email
和 message
字段。 它还确保 email
值使用有效电子邮件地址的格式。 它还确保 message
值的长度至少为 15 个字符。
如果这些表单要求中的任何一个未通过,则 valid
值将为 false
。 如果所有这些表单要求都通过,则 valid
的值将是 true
。
第 6 步 — 访问模板中的表单值和有效性
在模板中,您可以访问每个FormControl
的值和有效性以及整个表单组的值和有效性。
如果表单值无效,请重新访问 app.component.html
并使用 *ngIf
向用户显示反馈消息:
src/app/app.component.html
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)"> <div> <label> Name: <input formControlName="name" placeholder="Your name"> </label> <div *ngIf="myForm.get('name').invalid && (myForm.get('name').dirty || myForm.get('name').touched)"> Please provide a name. </div> </div> <div> <label> Email: <input formControlName="email" placeholder="Your email"> </label> <div *ngIf="myForm.get('email').invalid && (myForm.get('email').dirty || myForm.get('email').touched)"> Please provide a valid email address. </div> </div> <div> <label> Message: <input formControlName="message" placeholder="Your message"> </label> <div *ngIf="myForm.get('message').invalid && (myForm.get('message').dirty || myForm.get('message').touched)"> Messages must be at least 15 characters long. </div> </div> <button type="submit" [disabled]="myForm.invalid">Send</button> </form>
此代码检查用户是否与字段交互(dirty
或 touched
)。 然后,如果该值未通过验证要求,则会显示错误消息。 Send 按钮也将被禁用,直到表单值的所有问题都得到解决。
有多种方法可以检索表单控件值。 此示例使用 myForm.get('name')
等效于 myForm.controls.name
。 可以使用 .hasError('required')
或 .errors.required
检索错误信息。
结论
在本文中,您探索了如何将反应式表单应用于示例 Angular 应用程序。 您使用 FormControl
、FormGroup
、FormBuilder
和 Validators
构建了一个带有验证的示例表单。 更多功能请参考【X42X】官方文档【X68X】。
如果您想了解有关 Angular 的更多信息,请查看 我们的 Angular 主题页面 以获取练习和编程项目。