Angular 表单

本文介绍了Angular中的响应式表单和模板驱动表单,包括响应式表单的创建、表单控件的值获取与修改、数据流、表单验证,以及模板驱动表单的创建和验证。响应式表单适用于复杂场景,而模板驱动表单适合简单场景。
摘要由CSDN通过智能技术生成

表单

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

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

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

响应式表单

使用表单控件有三个步骤:

  1. 要使用 formControl,需要在模块中引入 ReactiveFormsModule;
  2. 在组件类中创建 FormControl实例 name;
  3. 在组件模板中 input标签上 绑定 [formControl]=“name”;将模板和组件类关联起来。
    在这里插入图片描述

在这里插入图片描述

获取表单控件的值

你可以用下列方式显示它的值:

  1. 通过可观察对象 valueChanges,你可以在模板中使用 AsyncPipe 或在组件类中使用 subscribe() 方法来监听表单值的变化。
  2. 使用 value 属性。它能让你获得当前值的一份快照。

在这里插入图片描述
在这里插入图片描述

修改表单控件的值

FormControl 提供了一个 setValue() 方法,它会修改这个表单控件的值,并且验证与控件结构相对应的值的结构。比如,当从后端 API 或服务接收到了表单数据时,可以通过 setValue() 方法来把原来的值替换为新的值。

  1. 组件中定义updateName方法,调用this.name.setValue设置新值;
  2. 模板中button绑定updateName方法;
    在这里插入图片描述

在这里插入图片描述

响应式表单中的数据流

在响应式表单中,视图中的每个表单元素都直接链接到一个表单模型(FormControl 实例)。 从视图到模型的修改以及从模型到视图的修改都是同步的,而且不依赖于 UI 的渲染方式。

视图—>模型

这个视图到模型的示意图展示了当输入字段的值发生变化时数据是如何从视图开始,经过下列步骤进行的:

  1. 最终用户在输入框元素中键入了一个值,这里是 “Blue”;
  2. 这个输入框元素会发出一个带有最新值的 “input” 事件;
  3. 这个控件值访问器 ControlValueAccessor 会监听表单输入框元素上的事件,并立即把新值传给 FormControl 实例;
  4. FormControl 实例会通过 valueChanges 这个可观察对象发出这个新值;
  5. valueChanges 的任何一个订阅者都会收到这个新值。
    在这里插入图片描述
模型—>视图

这个模型到视图的示意图体现了程序中对模型的修改是如何通过下列步骤传播到视图中的。

  1. favoriteColorControl.setValue() 方法被调用,它会更新这个 FormControl 的值。
  2. FormControl 实例会通过 valueChanges 这个可观察对象发出新值。
  3. valueChanges 的任何订阅者都会收到这个新值。
  4. 该表单输入框元素上的控件值访问器会把控件更新为这个新值。
    在这里插入图片描述

把表单控件分组

表单中通常会包含几个相互关联的控件。响应式表单提供了两种把多个相关控件分组到同一个输入表单中的方法。

  1. 表单组定义了一个带有一组控件的表单,你可以把它们放在一起管理。你也可以通过嵌套表单组来创建更复杂的表单。
  2. 表单数组定义了一个动态表单,你可以在运行时添加和删除控件。你也可以通过嵌套表单数组来创建更复杂的表单。

就像 FormControl 的实例能让你控制单个输入框所对应的控件一样,FormGroup 的实例能跟踪一组 FormControl 实例(比如一个表单)的表单状态。当创建 FormGroup 时,其中的每个控件都会根据其名字进行跟踪。

下面的例子展示了如何管理单个控件组中的多个 FormControl 实例。
在这里插入图片描述

保存表单数据

FormGroup 指令会监听 form 元素发出的 submit 事件,并发出一个 ngSubmit 事件,让你可以绑定一个回调函数。

  1. 把 onSubmit() 回调方法添加为 form 标签上的 ngSubmit 事件监听器。
  2. 组件中的 onSubmit() 方法会捕获 profileForm 的当前值。如果要保持该表单的封装性,就要使用 EventEmitter 向组件外部提供该表单的值。下面的例子会使用 console.log 把这个值记录到浏览器的控制台中。
  3. form 标签所发出的 submit 事件是内置 DOM 事件,通过点击类型为 submit 的按钮可以触发本事件。这还让用户可以用回车键来提交填完的表单。往表单的底部添加一个 button,用于触发表单提交。
    在这里插入图片描述
    在这里插入图片描述
创建嵌套的表单组

表单组可以同时接受单个表单控件实例和其它表单组实例作为其子控件。这可以让复杂的表单模型更容易维护,并在逻辑上把它们分组到一起。

如果要构建复杂的表单,如果能在更小的分区中管理不同类别的信息就会更容易一些。使用嵌套的 FormGroup 可以让你把大型表单组织成一些稍小的、易管理的分组。

要制作更复杂的表单,请遵循如下步骤。

  1. 创建一个嵌套的表单组。
  2. 在模板中对这个嵌套表单分组。
    在这里插入图片描述

在这里插入图片描述

更新部分数据模型

当修改包含多个 FormGroup 实例的值时,你可能只希望更新模型中的一部分,而不是完全替换掉。

有两种更新模型值的方式:

  1. 使用 setValue() 方法来为单个控件设置新值。 setValue() 方法会严格遵循表单组的结构,并整体性替换控件的值。setValue() 方法的严格检查可以帮助你捕获复杂表单嵌套中的错误,而 patchValue() 在遇到那些错误时可能会默默的失败。

  2. 使用 patchValue() 方法可以用对象中所定义的任何属性为表单模型进行替换。
    在这里插入图片描述

使用 FormBuilder 服务生成控件

当需要与多个表单打交道时,手动创建多个表单控件实例会非常繁琐。FormBuilder 服务提供了一些便捷方法来生成表单控件。FormBuilder 在幕后也使用同样的方式来创建和返回这些实例,只是用起来更简单。

FormBuilder 通过下列步骤来使用。

  1. 导入 FormBuilder 类。
  2. 注入这个 FormBuilder 服务。
  3. 生成表单内容。

FormBuilder 服务有三个方法:control()、group() 和 array()。这些方法都是工厂方法,用于在组件类中分别生成 FormControl、FormGroup 和 FormArray。
用 group 方法来创建 profileForm 控件:
在这里插入图片描述

注意: 你可以只使用初始值来定义控件,但是如果你的控件还需要同步或异步验证器,那就在这个数组中的第二项和第三项提供同步和异步验证器。

表单验证

官方文档
在响应式表单中,在组件类中把验证器函数添加到表单控件模型上(FormControl)。然后,一旦控件发生了变化,Angular 就会调用这些函数。

验证器(Validator)函数

验证器函数可以是同步函数,也可以是异步函数。

同步验证器:这些同步函数接受一个控件实例,然后返回一组验证错误或 null。可以在实例化一个 FormControl 时把它作为构造函数的第二个参数传进去

异步验证器 :这些异步函数接受一个控件实例并返回一个 Promise 或 Observable,它稍后会发出一组验证错误或 null。在实例化 FormControl 时,可以把它们作为第三个参数传入

出于性能方面的考虑,只有在所有同步验证器都通过之后,Angular 才会运行异步验证器。当每一个异步验证器都执行完之后,才会设置这些验证错误。

内置验证器函数

内置验证器列表

在这里插入图片描述
在这里插入图片描述

定义自定义验证器
/* 自定义验证器函数:通过传入的正则表达式判断其是否满足条件,结果是ValidatorFn类型(key: error)  */
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
   
  return (control: AbstractControl): ValidationErrors | null => {
   
    const forbidden = nameRe.test(control.value);
    return forbidden ? {
   forbiddenName: {
   value: control.value}} : null;
  };
}

在这里插入图片描述

在这里插入图片描述

跨字段交叉验证器

跨字段交叉验证器是一种自定义验证器,可以对表单中不同字段的值进行比较,并针对它们的组合进行接受或拒绝。
下面的例子是常见的注册场景时,密码和确认密码是否一致的校验。

  1. 首先要将两个字段注册在一个group中,group的第二个参数设置{validators: 自定义交叉验证器};
  2. 自定义交叉验证器和普通的验证器函数格式一样,区别就是从control中获不同的表单组件,然后对比其值是否满足要求。
    在这里插入图片描述
异步验证器

官方文档

异步验证器实现了 AsyncValidatorFn 和 AsyncValidator 接口。它们与其同步版本非常相似,但有以下不同之处。

validate() 函数必须返回一个 Promise 或可观察对象,返回的可观察对象必须是有尽的,这意味着它必须在某个时刻完成(complete)。要把无尽的可观察对象转换成有尽的,可以在管道中加入过滤操作符,比如 first、last、take 或 takeUntil。

异步验证只有在同步验证成功时才会执行。异步验证开始之后,表单控件就会进入 pending 状态,可以检查控件的 pending 属性,并用它来给出对验证中的视觉反馈。一种常见的 UI 模式是在执行异步验证时显示 Spinner(转轮)。下面的例子展示了如何在模板驱动表单中实现这一点。

<input [(ngModel)]="name" #model="ngModel" appSomeAsyncValidator>
<app-spinner *ngIf="model.pending"></app-spinner>

如下示例,注册时用户输入的手机号需要在后台校验是否已经存在。

  1. 创建一个服务用于给后台发请求校验;继承AsyncValidator;
  2. 需要实现validate方法,返回值是null或promise或Observable;
  3. 异步校验设置在FormControl 第三个参数;
    在这里插入图片描述

在这里插入图片描述

默认情况下,所有验证程序在每次表单值更改后都会运行。对于同步验证器,这通常不会对应用性能产生明显的影响。但是,异步验证器通常会执行某种 HTTP 请求来验证控件。每次按键后调度一次 HTTP 请求都会给后端 API 带来压力,应该尽可能避免。
可以通过以下方式将触发的时机改为控件失去焦点时触发:
在这里插入图片描述

模板驱动表单

官方文档

创建模板驱动型表单

  1. 引入FormModules;
  2. 在form标签上通过 #profileForm=“ngForm”,创建NgForm实例,并将其赋值给profileForm;
  3. profileForm就是NgForm类型, profileForm.form是FormGroup实例
  4. 在表单控件中,使用ngModel 创建 FormControl 实例,并通过name="***" 将其注
Angular 表单验证是一种在 Web 应用程序中对用户输入进行验证的方法。它可以防止用户在提交表单之前输入不正确的数据。在 Angular 中,表单验证是通过构建验证器函数并将其应用于表单控件来完成的。以下是一个简单的例子,演示如何在 Angular 中应用表单验证: 1. 在 HTML 模板中定义表单: ```html <form (ngSubmit)="onSubmit()" #myForm="ngForm"> <label> Name: <input type="text" name="name" ngModel required> </label> <label> Email: <input type="email" name="email" ngModel required email> </label> <button type="submit" [disabled]="!myForm.form.valid">Submit</button> </form> ``` 2. 在组件中定义验证器函数: ```typescript import { Component } from '@angular/core'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.css'] }) export class FormComponent { myForm: FormGroup; constructor(private fb: FormBuilder) { this.myForm = this.fb.group({ name: ['', Validators.required], email: ['', [Validators.required, Validators.email]] }); } onSubmit() { console.log(this.myForm.value); } } ``` 在上面的代码中,我们使用 `FormBuilder` 创建了一个名为 `myForm` 的表单,并添加了两个控件:`name` 和 `email`。`name` 控件是必填的,而 `email` 控件则需要符合电子邮件格式。在 `onSubmit` 方法中,我们可以访问表单的值,并进行进一步的处理。 值得注意的是,为了让表单控件与模板中的 `ngModel` 指令进行绑定,我们需要在组件中导入 `FormsModule` 模块。在模板中,我们还使用了 Angular 的模板语法,如 `ngSubmit` 事件和 `[disabled]` 属性,来控制表单的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值