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.绑定验证器用于校验长度和必填

SuperCms在线订餐系统
SuperCms在线订餐系统

模板采用响应式设计,自动适应手机,电脑及平板显示;满足单一店铺外卖需求。功能:1.菜单分类管理2.菜品管理:菜品增加,删除,修改3.订单管理4.友情链接管理5.数据库备份6.文章模块:如:促销活动,帮助中心7.单页模块:如:企业信息,关于我们更强大的功能在开发中……安装方法:上传到网站根目录,运行http://www.***.com/install 自动

下载

实现步骤

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语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

237

2023.09.22

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

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

458

2024.03.01

promise的用法
promise的用法

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

306

2023.10.12

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

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

406

2023.10.12

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

9

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

9

2026.01.30

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

8

2026.01.30

python 字符串格式化
python 字符串格式化

本专题整合了python字符串格式化教程、实践、方法、进阶等等相关内容,阅读专题下面的文章了解更多详细操作。

3

2026.01.30

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

20

2026.01.29

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
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号