如何在 Angular 中使用响应式表单

简介

Angular 提供了两种处理表单的方式:模板驱动表单响应式表单 (也称为 模型驱动表单)。模板驱动表单是在 Angular 中处理表单的默认方式。使用模板驱动表单时,模板指令被用来构建表单的内部表示。而使用响应式表单时,你需要在组件类中构建自己的表单表示。

以下是响应式表单的一些优势:

  • 使用自定义验证器
  • 动态改变验证规则
  • 动态添加表单字段

在本文中,你将探索如何将响应式表单应用到一个示例 Angular 应用程序中。

先决条件

如果你想跟着本文操作,你需要:

  • 本地安装 Node.js,你可以按照《如何安装 Node.js 并创建本地开发环境》进行操作。

本文假设你具有一些 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 项目开始构建。

command 复制代码
npx @angular/cli new angular-reactive-forms-example --style=css --routing=false --skip-tests

这将配置一个新的 Angular 项目,其中样式设置为 "CSS"(而不是 "Sass"、"Less" 或 "Stylus"),没有路由,并且跳过了测试。

进入新创建的项目目录:

command 复制代码
cd angular-reactive-forms-example

为了使用响应式表单,你将使用 ReactiveFormsModule 而不是 FormsModule

在你的代码编辑器中打开 app.module.ts 并添加 ReactiveFormsModule

typescript 复制代码
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 并添加以下代码:

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>

这段代码将创建一个包含三个字段(nameemailmessage)的表单。还将有一个标签为 "Send" 的 "submit" 按钮。在提交表单时,将调用 onSubmit(myForm) 方法。

让我们来分解一下:

  • formGroup:表单将在组件类中被视为 FormGroup,因此 formGroup 指令允许给表单组指定一个名称。
  • ngSubmit:这是在提交表单时触发的事件。
  • formControlName:每个表单字段应该有一个 formControlName 指令,其值将在组件类中使用。

到此为止,你应该已经有了一个使用表单的组件模板。

步骤 3 ------ 构建组件类

接下来,在组件类中,你将定义 FormGroupFormGroup 内的各个 FormControl

如果在 newing FormControl 时提供了一个值,它将被用作字段的初始值。

注意 FormGroupFormControl 的名称与模板中使用的名称相同。还要注意你如何在 ngOnInit 生命周期钩子中初始化 FormGroup

typescript 复制代码
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 浏览器中打开它。在为 nameemailmessage 输入值并点击 Submit 后,控制台日志将显示这些值。

第四步 --- 更新组件类以使用 FormBuilder

ngOnInit 中的表单构建可以使用 FormBuilder 辅助程序进行重写。这样可以避免对表单组和表单控件进行 newing

在代码编辑器中打开 app.component.ts,移除 FormControl 并用 FormBuilder 替换 FormGroup

typescript 复制代码
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 的样板代码。

第五步 --- 更新组件类以使用 Validators

Validators 类添加到你的导入中,并使用数组而不是简单的字符串值来声明表单控件。

数组中的第一个值是初始表单值,第二个值是要使用的验证器。请注意,可以通过将它们包装成数组来在同一个表单控件上使用多个验证器。

在代码编辑器中打开 app.component.ts,添加 Validators

typescript 复制代码
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);
  }
}

这段代码为 nameemailmessage 字段添加了 required。它还确保 email 值使用有效电子邮件地址的格式。它还确保 message 值至少为 15 个字符长。

如果这些表单要求中的任何一个未通过,valid 值将为 false。如果所有这些表单要求都通过,valid 值将为 true

第六步 --- 在模板中访问表单值和有效性

在模板中,可以访问每个 FormControl 的值和有效性,以及整个表单组的值和有效性。

打开 app.component.html,使用 *ngIf 来显示反馈消息,告诉用户表单值无效:

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>

这段代码检查用户是否与字段交互(dirtytouched)。然后,如果值未通过验证要求,它将显示错误消息。Send 按钮也将在解决表单值的所有问题之前被禁用。

有多种方法可以检索表单控件的值。此示例使用 myForm.get('name'),它等同于 myForm.controls.name。可以使用 .hasError('required').errors.required 检索错误信息。

结论

在本文中,您探讨了如何将响应式表单应用于一个示例 Angular 应用程序。您使用了 FormControlFormGroupFormBuilderValidators 来构建一个带有验证的示例表单。如需了解更多功能,请参考官方文档。

如果您想了解更多关于 Angular 的知识,请查看我们的 Angular 专题页面,了解相关练习和编程项目。

相关推荐
暮紫李12 分钟前
项目中如何强制使用pnpm
前端
哈哈哈笑什么14 分钟前
如何防止恶意伪造前端唯一请求id
前端·后端
Tzarevich15 分钟前
JavaScript 作用域与执行机制:从变量提升到块级作用域的演进
javascript·v8
kevinzzzzzz17 分钟前
基于模块联邦打通多系统的探索
前端·javascript
季禮祥18 分钟前
彻底弄懂KeepAlive
javascript·vue.js·面试
小胖霞20 分钟前
彻底搞懂 JWT 登录认证与路由守卫(五)
前端·vue.js·node.js
用户938169125536022 分钟前
VUE3项目--组件递归调用自身
前端
昔人'30 分钟前
CSS content-visibility
前端·css
灵魂学者36 分钟前
Vue3.x —— ref 的使用
前端·javascript·vue.js