0

0

一文浅析Angular中的响应式表单

青灯夜游

青灯夜游

发布时间:2022-04-25 10:26:40

|

3580人浏览过

|

来源于掘金社区

转载

本篇文章带大家聊聊angular中的响应式表单,通过实例来介绍一下简单的表单实现方法,希望对大家有所帮助!

一文浅析Angular中的响应式表单

由于最近公司框架升级,抛弃了原来手动检验表单的方式,将所有的表单改为响应式,由于之前没用过,在一开始我以为只有我没有用过,了解了小组里的其他同事得知基本都不是很熟悉

后面时间比较紧,没办法只能边做边学边改了,所以难免踩了一些坑,当然也花了一些时间学习,虽然对于熟悉的人来说可能很简单,但是还是将学习的过程和小结以及解决的问题的方法总结一下,也算是一种提炼。在这里更多的是理论结合实际业务需求来说,而不是一味的按照官方文档的方式写API介绍,如果那样就是学习笔记,而不是总结了。

为什么主要介绍响应式表单呢?因为响应式表单提供对底层表单对象模型直接、显式的访问。它们与模板驱动表单相比,更加健壮:它们的可扩展性、可复用性和可测试性都更高。适用于比较复杂的表单,其实最重要的是其他的我也不会呀。【相关教程推荐:《angular教程》】

一、响应式表单基本概念

1.FormControl  、FormArray 、FormGroup

1.FormControl:  用于追踪单个表单控件的值和验证状态,例如一个栏位绑定

//初始化一个栏位的值为测试名字,并且不可用
const Name:FormControl = new FormControl({value:'测试名字', disabled: true });

2.FormArray:用于追踪表单控件数组的值和状态,例如几个栏位一起,常用的表格或者在表单中嵌入表格

//定义表单对象的属性为aliases的FormArray 
this.validateForm = this.fb.group({aliases: this.fb.array([]),});

//获取FormArray 
get aliases() {return this.validateForm.get('aliases') as FormArray;}

//给FormArray 添加item
this.aliases.push(
  this.fb.group({Id: 0,Name: [null],})
);

3.FormGroup:用于追踪单个表单控件的值和验证状态,它可以包含单个或多个FormControl 和 FormArray ,一般一个表单对应一个FormGroup实例,而表单的各个栏位对应FormControl  和FormArray ,当然他们可以互相嵌套,例如FormArray 中可以嵌套FormGroup,它的灵活性就是如此。

validateForm =  new FormGroup({Name: new FormControl({value:'测试名字', disabled: true }),});
validateForm = this.fb.group({});

4.FormBuilder:是一个可注入的服务提供者,手动创建多个表单控件实例会非常繁琐,FormBuilder 服务提供了一些便捷方法来生成表单控件,以前每一个创建要先生成FormGroup 然后生成FormControl,而使用FormBuilder的group方法可以减少重复代码,说白了就是帮助方便生成表单

validateForm!: FormGroup;
//手动创建
validateForm = new FormGroup({
    Name: new FormControl('测试名字'),
  });
  
//FormBuilder表单构建器
validateForm = this.fb.group({
  Name:[ { value:'测试名字',disabled:true}],
});

2.Validator 表单验证

表单验证用于确保用户的输入是完整和正确的。如何把单个验证器添加到表单控件中,以及如何显示表单的整体状态,通常验证器返回null表示所有的验证通过。

1.同步验证器:同步验证器函数接受一个控件实例,然后返回一组验证错误或 null,在实例化FormControl 时可以将他作为第二个参数传入

 //formControlName的值必须和ts代码中FormControl 的实例一致
 
 
 //判断对应的FormControl 是否没通过校验 而有错误信息
 
Name is required.
//初始化一个栏位并且加入必填校验验证器
const name:FormControl = new FormControl({'测试名字', disabled: true },Validators.required,);

//获取这个FormControl
get name() { return this.heroForm.get('name'); }

2.异步验证器:异步函数接受一个控件实例并返回一个 Promise 或 Observable ,只有在所有同步验证器都通过之后,Angular 才会运行异步验证器,在实例化FormControl 时可以将他作为第三个参数传入

3.内置验证器:例如验证一些长度,不能为空可以使用已经提供的Validator 类来实现

4.自定义验证器:系统内部提供的验证器不能满足现有需求,可以使用自定义验证器做一些个性化的校验,自定义校验器必须返回ValidationErrors类型或者空

 //formControlName的值必须和ts代码中FormControl 的实例一致
 
 
 //判断对应的FormControl 是否没通过校验 而有错误信息
 
名字也太长了吧....
//初始化一个栏位并且加入必填校验验证器
const name:FormControl = new FormControl({'测试名字', disabled: true },this.CustomValidators());

CustomValidators() {
 return (control: AbstractControl): ValidationErrors | null => {
    if(control.value.length!=10)
      {
        return {Invalid:true}
      }
      return null;
    };
}

3.表单及元素的基本方法和属性

  • 方法
方法 使用效果
setValue() 使用setVlue可以设置控件FormControl  的值,但是使用时必须FormGroup所有的属性一起赋值,不能单个赋值,常用在修改加载赋值。
patchValue() 使用patchValue也可以设置FormControl的值,可以根据需要设置指定的FormControl,而不需要全部设置,常用在更新某个字段值
reset () FormControl 中使用重置当前控件所有状态,FormGroup中使用就是重置表单对象里的内容,例如控件被设为不可用disabled,control.reset({ value: 'Drew', disabled: true });
markAsPristine() 是将表单控件值标记为未改变,这个方法主要用在表单重置时,此时它的状态pristine为true
markAsDirty() 是将表单FormControl 控件值标记为已改变,此时它的状态Dirty为true
updateValueAndValidity() 重新计算表单FormControl 控件的值和验证状态等
setValidators() 给表单FormControl 控件设置验证器,如果设置多个就用数组"setValidators([v1,v2,v3])"
disable() 给表单FormControl 控件设置不可用,注意当FormControl 是disabled时,表单的常规取值getValue()对应值会为空,可用getRawValue()取原始值对象得到对应FormControl 的值
enable() 给表单FormControl 控件设置启用
  • 属性

属性 使用方法说明
touched 当表单FormControl 控件 的touched为true表示控件已经被获取焦点,反之同理
untouched 当untouched 为true表示控件未被获取焦点,反之同理
pristine 表示表单元素是纯净的,用户未操作过,可以使用markAsPristine方法设为true
dirty 表示表单元素是已被用户操作过,可以使用markAsDirty方法设为true
status 获取表单FormControl 控件上的的状态
Errors 获取当前控件的错误信息

二.实例分析及应用

1. 简单的表单实现

######需求1

我们主要用到的框架版本是Angular 12 + NG-ZORRO, 所以在下面很多实现和示例代码将与他们有关,虽然可能代码不一样,但也只是在UI层面的区别稍微大一点点,但对于TS代码,只是换汤不换药,稍微注意一下就好了,其实下面实例中的需求,基本就是我在工作时需要做的的一些基本内容和遇到的问题,经过查阅资料后解决的思路和过程,甚至截图都一模一样。

实现最基本的表单新增功能并且校验员工ID为必填以及长度不能超过50,要实现的效果图如下

1.png

分析

1.首先需求未提出有特殊注意点,基本都是简单的输入框赋值然后保存,只要基本的概念搞清楚实现这种最简单

2.我们用一个FormGroup和6个FormControl 完成和界面绑定即可

3.绑定验证器用于校验长度和必填

jQuery响应式下拉导航菜单项
jQuery响应式下拉导航菜单项

jQuery响应式下拉导航菜单项,一款黑色的导航,鼠标放在一级目录会显示二级目录,很适用于企业网站或者商城网站,php中文网推荐下载!

下载

实现步骤

1.定义html 表单结构


Employee ID 员工编号为必填项目

2.在TypeScript代码中声明表单对象,在构造函数中注入FormBuilder,并且在ngOnInit中进行表单初始化

//定义表单对象
validateForm:FormGroup;

//构造函数注入FormBuilder
constructor(private fb: FormBuilder){}

//在声明周期钩子函数中初始化表单
ngOnInit() {
  //初始化并且绑定必填验证器和长度验证器

    this.validateForm = this.fb.group({
      EmployeeID: ['', [Validators.required, Validators.maxLength(50)]],  
    })
}

2.在表格中应用表单

需求2

需要实现表格的表单新增和提交以及个性化定制需求,要实现的效果图和需求描述如下

1.点击Add 添加一行表格 ,编辑完毕,点击Save保存数据,点击Revoke取消编辑

2.默认开始时间和结束时间禁止使用

3.当选择Contract Type为 “短期合同” Contract start date 和Contract end date可用,当选择Contract Type为 “长期合同”不可用

4.如果Contract start date 和Contract end date可用,需要验证开始结束时间合法性,例如开始事件不能超过结束时间

2.png

分析

1.在表格中使用表单,虽然表单在表格中,但是他的每一列同样都是一个个FormControl

2.一共4列需要输入值,就说明有4个FormControl 然后最后一列就是2个按钮

3.我们根据上面的基础知识知道,FormControl 不能单独使用,所以需要被FormGroup包裹,此时说明一行对应一个FormGroup

4.由一行对应一个FormGroup知道,我们的表格时多行的,也就是有多个FormGroup,我们可以使用FormArray来存储,因为他代表一组表单组

5.根据需求第2点默认开始时间和结束时间禁止使用,我们知道在一开始初始化时,设置开始结束时间对应的FormControl 为disabled就行了

6.第3点需求需要涉及联动,也就是当Contract Type对应的FormControl 的值为“短期合同”时,需要将 “开始结束时间”对应的FormControl设置为可用,这个需要自定义验证器来完成

实现步骤

1.首先定义Html表单结构


  
    
      Contract type
      Contract start date
      Contract end date
      Agreement item
      Operation
    
  

  
    
    
      
      
        
          
            
              
              
                
                
              
            
          
          
            
              
              
              
              
              	
                
                  开始时间不能晚于结束时间
                
              
            
          
          
            
              
              
              
                
                  开始时间不能晚于结束时间
                
              
            
          
          
            
              
                
                
              
            
          
        
        
          
          
        
      
    
  

2.在TypeScript代码中声明表单对象validateForm,然后初始化一个FormArray类型的属性aliases的实例作为表格formArrayName的值

3.点击Add按钮时向表单对象validateForm的属性aliases添加一条数据

4.定义Contract Type 联动的自定义校验器 contractTypeValidation()方法

5.定义时间校验器 timeValidation()方法,如果时间不合法,将FormControl的错误状态设置属性beginGtendDate,然后在模板中根据这个属性来选择是否渲染日式信息

//定义表单对象
validateForm:FormGroup;
//构造函数注入FormBuilder
constructor(private fb: FormBuilder){}

//在声明周期钩子函数中初始化一个表单对象validateForm
ngOnInit() {
this.validateForm = this.fb.group({
      aliases: this.fb.array([]),
 	});
}
//声明aliases属性用作界面formArrayName绑定
get aliases(){
	return this.validateForm.get('aliases') as FormArray;
}

addNewRow() {
  const group = this.fb.group({
    //添加给Type初始化验证器
    Type: [null, [CommonValidators.required, this.contractTypeValidation()]],
    //初始化禁用StartDate和EndDate的FormControl 
    StartDate: [{ value: null, disabled: true }, []],
    EndDate: [{ value: null, disabled: true },[]],
    ContractType: [null, [CommonValidators.required, CommonValidators.maxLength(20)]],
  })
  this.aliases.push(group);
}

  //自定义Contract Type验证器
contractTypeValidation() {
    return (control: AbstractControl): ValidationErrors | null => {
      let contents: any[] = this.validateForm.value.aliases;
      if (control.touched && !control.pristine) {
        //获取表单组
        const formArray: any = this.validateForm.controls.aliases;
        //找到正在编辑的行的索引
        const index = contents.findIndex((x) => !x.isShowEdit);

        //获取开始结束时间FormControl 实例
        const StartDate: AbstractControl =
          formArray.controls[index].get('StartDate'),
          EndDate: AbstractControl = formArray.controls[index].get('EndDate');

        if (control.value === "短期合同") {
          //给开始结束时间设置验证器用于验证时间合法性
          StartDate.setValidators([CommonValidators.required, this.timeValidation()]);
          EndDate.setValidators([this.timeValidation()]);

          //启动开始结束时间控件
          EndDate.enable();
          StartDate.enable();
        } else {
          //Contract Type不是短期合同就清除验证器
          StartDate.clearValidators();
          EndDate.clearValidators();
          //禁用开始结束时间
          EndDate.disable();
          StartDate.disable();
        }

      }
      return null;
    }
  }



  //自定义时间验证器
 timeValidation()
  {
    return (control: AbstractControl): ValidationErrors | null => {
      if (!control.pristine) {
        let contents: any[] = this.validateForm.value.aliases;
        const formArray: any = this.validateForm.controls.aliases;
        const index = contents.findIndex((x) => !x.isShowEdit);
        //获取开始结束时间FormControl实例
        const EndDate: string = formArray.controls[index].get('EndDate').value;
        const StartDate: string =formArray.controls[index].get('StartDate').value;

        if (EndDate === null || StartDate === null) return null;

        //如果时间不合法,那就设置当前控件的错误状态 beginGtendDate为true
        if (
          Date.parse(control.value) > Date.parse(EndDate) ||
          Date.parse(control.value) < Date.parse(StartDate)
        ) {
          return { beginGtendDate: true };
        }
      }
      return null;
    }
  }

更多编程相关知识,请访问:编程入门!!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

238

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

519

2024.03.01

promise的用法
promise的用法

“promise” 是一种用于处理异步操作的编程概念,它可以用来表示一个异步操作的最终结果。Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。Promise的用法主要包括构造函数、实例方法(then、catch、finally)和状态转换。

307

2023.10.12

html文本框类型介绍
html文本框类型介绍

html文本框类型有单行文本框、密码文本框、数字文本框、日期文本框、时间文本框、文件上传文本框、多行文本框等等。详细介绍:1、单行文本框是最常见的文本框类型,用于接受单行文本输入,用户可以在文本框中输入任意文本,例如用户名、密码、电子邮件地址等;2、密码文本框用于接受密码输入,用户在输入密码时,文本框中的内容会被隐藏,以保护用户的隐私;3、数字文本框等等。

409

2023.10.12

AO3官网入口与中文阅读设置 AO3网页版使用与访问
AO3官网入口与中文阅读设置 AO3网页版使用与访问

本专题围绕 Archive of Our Own(AO3)官网入口展开,系统整理 AO3 最新可用官网地址、网页版访问方式、正确打开链接的方法,并详细讲解 AO3 中文界面设置、阅读语言切换及基础使用流程,帮助用户稳定访问 AO3 官网,高效完成中文阅读与作品浏览。

60

2026.02.02

主流快递单号查询入口 实时物流进度一站式追踪专题
主流快递单号查询入口 实时物流进度一站式追踪专题

本专题聚合极兔快递、京东快递、中通快递、圆通快递、韵达快递等主流物流平台的单号查询与运单追踪内容,重点解决单号查询、手机号查物流、官网入口直达、包裹进度实时追踪等高频问题,帮助用户快速获取最新物流状态,提升查件效率与使用体验。

22

2026.02.02

Golang WebAssembly(WASM)开发入门
Golang WebAssembly(WASM)开发入门

本专题系统讲解 Golang 在 WebAssembly(WASM)开发中的实践方法,涵盖 WASM 基础原理、Go 编译到 WASM 的流程、与 JavaScript 的交互方式、性能与体积优化,以及典型应用场景(如前端计算、跨平台模块)。帮助开发者掌握 Go 在新一代 Web 技术栈中的应用能力。

10

2026.02.02

PHP Swoole 高性能服务开发
PHP Swoole 高性能服务开发

本专题聚焦 PHP Swoole 扩展在高性能服务端开发中的应用,系统讲解协程模型、异步IO、TCP/HTTP/WebSocket服务器、进程与任务管理、常驻内存架构设计。通过实战案例,帮助开发者掌握 使用 PHP 构建高并发、低延迟服务端应用的工程化能力。

3

2026.02.02

Java JNI 与本地代码交互实战
Java JNI 与本地代码交互实战

本专题系统讲解 Java 通过 JNI 调用 C/C++ 本地代码的核心机制,涵盖 JNI 基本原理、数据类型映射、内存管理、异常处理、性能优化策略以及典型应用场景(如高性能计算、底层库封装)。通过实战示例,帮助开发者掌握 Java 与本地代码混合开发的完整流程。

4

2026.02.02

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue.js:纪录片
Vue.js:纪录片

共1课时 | 0.2万人学习

Angular js入门篇
Angular js入门篇

共17课时 | 3.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号