Angular表单

1,137 阅读4分钟

Angular 表单简介

用表单处理用户输入是许多常见应用的基础功能。 应用通过表单来让用户登录、修改个人档案、输入敏感信息以及执行各种数据输入任务。

Angular 提供了两种不同的方法来通过表单处理用户输入:响应式表单模板驱动表单。 两者都从视图中捕获用户输入事件、验证用户输入、创建表单模型、修改数据模型,并提供跟踪这些更改的途径。

本文提供的信息可以帮你确定哪种方式最适合你的情况。它介绍了这两种方法所用的公共构造块,还总结了两种方式之间的关键区别,并在建立、数据流和测试等不同的情境下展示了这些差异。

选择一种方法

响应式表单和模板驱动表单以不同的方式处理和管理表单数据。每种方法都有各自的优点。

  • 响应式表单提供对底层表单对象模型直接、显式的访问。它们与模板驱动表单相比,更加健壮:它们的可扩展性、可复用性和可测试性都更高。如果表单是你的应用程序的关键部分,或者你已经在使用响应式表单来构建应用,那就使用响应式表单。

  • 模板驱动表单依赖模板中的指令来创建和操作底层的对象模型。它们对于向应用添加一个简单的表单非常有用,比如电子邮件列表注册表单。它们很容易添加到应用中,但在扩展性方面不如响应式表单。如果你有可以只在模板中管理的非常基本的表单需求和逻辑,那么模板驱动表单就很合适。

关键差异

下表总结了响应式表单和模板驱动表单之间的一些关键差异。

响应式模板驱动
建立表单模型显式的,在组件类中创建隐式的,由指令创建
数据模型结构化和不可变的非结构化和可变的
建立表单模型同步异步
建立表单模型函数指令

可伸缩性

如果表单是应用程序的核心部分,那么可伸缩性就非常重要。能够跨组件复用表单模型是至关重要的。

响应式表单比模板驱动表单更有可伸缩性。它们提供对底层表单 API 的直接访问,并且在视图和数据模型之间使用同步数据流,从而可以更轻松地创建大型表单。响应式表单需要较少的测试设置,测试时不需要深入理解变更检测,就能正确测试表单更新和验证。

模板驱动表单专注于简单的场景,可复用性没那么高。它们抽象出了底层表单 API,并且在视图和数据模型之间使用异步数据流。对模板驱动表单的这种抽象也会影响测试。测试程序非常依赖于手动触发变更检测才能正常运行,并且需要进行更多设置工作。

建立表单模型

响应式表单和模板驱动型表单都会跟踪用户与之交互的表单输入元素和组件模型中的表单数据之间的值变更。这两种方法共享同一套底层构建块,只在如何创建和管理常用表单控件实例方面有所不同。

常用表单基础类

响应式表单和模板驱动表单都建立在下列基础类之上。

  • FormControl 实例用于追踪单个表单控件的值和验证状态。

  • FormGroup 用于追踪一个表单控件组的值和状态。

  • FormArray 用于追踪表单控件数组的值和状态。

  • ControlValueAccessor 用于在 Angular 的 FormControl 实例和原生 DOM 元素之间创建一个桥梁。

建立响应式表单

对于响应式表单,你可以直接在组件类中定义表单模型。[formControl] 指令会通过内部值访问器来把显式创建的 FormControl 实例与视图中的特定表单元素联系起来。

下面的组件使用响应式表单为单个控件实现了一个输入字段。在这个例子中,表单模型是 FormControl 实例。

import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-reactive-favorite-color',
  template: `
    Favorite Color: <input type="text" [formControl]="favoriteColorControl">
  `
})
export class FavoriteColorComponent {
  favoriteColorControl = new FormControl('');
}

建立模板驱动表单

在模板驱动表单中,表单模型是隐式的,而不是显式的。指令 NgModel 为指定的表单元素创建并管理一个 FormControl 实例。

下面的组件使用模板驱动表单为单个控件实现了同样的输入字段。

import { Component } from '@angular/core';

@Component({
  selector: 'app-template-favorite-color',
  template: `
    Favorite Color: <input type="text" [(ngModel)]="favoriteColor">
  `
})
export class FavoriteColorComponent {
  favoriteColor = '';
}