FormArray在动态表格中的应用

news2024/11/18 6:44:31

如下图,是这次想要实现的功能。

  一个表格行,点击新增按钮就增加一行,点击后面的删除按钮就可以删除对应的行,其中有部分字段需要添加非空校验。要想实现这个功能,需要应用到FormArray的知识。

步骤:

1. 声明一个FormGroup,里面包含FormArray,FormArray里面嵌套一组FormControl,由FormGroup管理

inputEnergyForm: FormGroup = new FormGroup({
    inputEnergy: new FormArray([])
})

2. 添加一个属性,名字叫 inputEnergy,是一个get形式的属性。这样通过this.contacts就可以直接找到FormArray。

get inputEnergy () {
    return this.inputEnergyForm.get('inputEnergy') as FormArray
}

3. 添加表单组的方法

addInputEnergy () {
    // 新增下一行之前先验证当前行
    if (this.inputEnergyForm.valid) {
      // 创建表单组由FormGroup管理并初始化行数据
      const inputEnergy: FormGroup = new FormGroup({
        typeCode: new FormControl(null, Validators.required), // 必填
        typeName: new FormControl(null), // 非必填,默认值为null
        unit: new FormControl(null),
        usage: new FormControl(null, Validators.required),
        equivalentCoefficient: new FormControl(0, Validators.required),
        coalUnit: new FormControl(null),
        equivalentValue: new FormControl(0),
        equalCoefficient: new FormControl(0),
        equalValue: new FormControl(0)
      })
      // 把新增的表单组添加到FormArray
      this.inputEnergy.push(inputEnergy)
      // 正常不需要这行代码的,但是不知道为啥我的项目只有这么写才会触发数据的重新渲染
      this.inputEnergy.controls = [...this.inputEnergy.controls]
    } else {
      // 未通过验证的红字提示未通过验证原因
      for (const i in this.inputEnergy.controls) {
        // 不同结构的FormGroup验证方法略有不同,写了一个共通的方法。
        this.markFormDirty(<FormGroup>this.inputEnergy.controls[i])
      }
    }
  }

4. 删除表单组的方法

delInputEnergy(i: number) {
    // 通过下标移除
    this.inputEnergy.removeAt(i)
    // 正常不需要这行代码的,但是不知道为啥我的项目只有这么写才会触发数据的重新渲染
    this.inputEnergy.controls = [...this.inputEnergy.controls]
  }

5. 回显表单组的方法

initInputEnergyInfo() {
    if (this.energyInfo.inputEnergy) {
      this.energyInfo.inputEnergy.forEach((item: any, index: number) => {
        const inputEnergy: FormGroup = new FormGroup({
          typeCode: new FormControl(item.typeCode, Validators.required),
          typeName: new FormControl(item.typeName),
          unit: new FormControl(item.unit),
          usage: new FormControl(item.usage, Validators.required),
          equivalentCoefficient: new FormControl(item.equivalentCoefficient, Validators.required),
          coalUnit: new FormControl(item.coalUnit),
          equivalentValue: new FormControl(item.equivalentValue),
          equalCoefficient: new FormControl(item.equalCoefficient),
          equalValue: new FormControl(item.equalValue)
        })
        this.inputEnergy.insert(index, inputEnergy)
        this.inputEnergy.controls = [...this.inputEnergy.controls]
      })
    }
  }

6. 自定义表单验证

FormGroup = new FormGroup({
    value: new FormControl(item.value, [Validators.required, this.isMoreThanZero])
})

// 在非空验证基础上额外添加数字必须大于0的表单验证
isMoreThanZero(control: FormControl) {
    if (isNaN(Number(control.value)) || control.value <= 0) {
      // 注意,这里返回的是isMoreThanZero,才能对应.hasError('isMoreThanZero')
      return {  isMoreThanZero: true };
    }
    return null
  }

共通的触发验证方法

markFormDirty(form: FormGroup) {
    this.markGroupDirty(form);
  }

  markControlDirty(formControl: FormControl, key: string) {
    formControl.markAsDirty();
    formControl.updateValueAndValidity();
    if (formControl.invalid) {
      console.log(`invalid key: ${key}`);
    }
  }

  markGroupDirty(formGroup: FormGroup) {
    Object.keys(formGroup.controls).forEach(key => {
      switch (formGroup?.get(key)?.constructor?.name) {
        case 'FormGroup':
          this.markGroupDirty(formGroup.get(key) as FormGroup);
          break;
        case 'FormArray':
          this.markArrayDirty(formGroup.get(key) as FormArray, key);
          break;
        case 'FormControl':
          this.markControlDirty(formGroup.get(key) as FormControl, key);
          break;
      }
    })
  }

  markArrayDirty(formArray: FormArray, key: string) {
    formArray.controls.forEach(control => {
      switch (control.constructor.name) {
        case 'FormGroup':
          this.markGroupDirty(control as FormGroup);
          break;
        case 'FormArray':
          this.markArrayDirty(control as FormArray, key);
          break;
        case 'FormControl':
          this.markControlDirty(control as FormControl, key);
          break;
      }
    });
  }

此次开发采用父子组件开发模式,涉及了父子组件通信。

① 父组件传递给子组件数据

在父组件的模板中插入子组件模板,并将父组件中的energyInfo传递给子组件。

<div>
    <app-energy-form [energyInfo]="energyInfo"></app-energy-form>
</div>

子组件接收energyInfo

@Input() energyInfo: any

② 子组件传递给父组件数据并调用父组件的方法

在子组件处理好数据之后通过调用父组件的receiveEnergyInfo方法的方式将energyInfo作为参数回传给父组件。

子组件

@Output() reback = new EventEmitter<any>()

this.reback.emit(energyInfo)

父组件在引用子组件标签处添加 reback 属性

<div>
    <app-energy-form (reback)="receiveEnergyInfo($event)"></app-energy-form>
</div>

并在ts中声明对应方法receiveEnergyInfo 

receiveEnergyInfo(info: any) {
    console.log('父组件收到子组件的回传数据',info)
}

③ 父组件调用子组件的方法

点击父组件中的提交按钮可以手动触发子组件的表单验证

在父组件引入子组件标签处可以给子组件标签起个标识 #energyForm

<app-energy-form #energyForm></app-energy-form>

这样就可以在父组件中通过 energyForm. 的方式,调用子组件的check方法了。

this.energyForm.check()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/192152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

打开IE浏览器自动跳转到Edge的解决方法

场景Windows 10中&#xff0c;打开IE浏览器自动跳转到Edge&#xff0c;但是某些网站还是只能在IE中正常访问&#xff0c;Edge访问会出问题。解决方案Edge中点击右上角的三个点&#xff0c;然后点击设置在“默认浏览器”中&#xff0c;修改“让 Internet Explorer 在 Microsoft …

Linux-文件和目录常用命令

1.查看目录内容1.1 终端使用技巧自动补全在敲出 文件/目录/命令的前几个字母之后&#xff0c;按下tab键如果输入的没有歧义&#xff0c;系统会自动补全如果还存在其他文件/目录/命令,再按一下tab键,系统会提示可能存在的命令曾经使用过的命令按上/下光标键可以再曾经使用过的命…

GeoServer系列-安装SqlServer插件

GeoServer 安装包中是不含sqlserver插件的&#xff0c;所以无法创建sqlserver的数据存储&#xff0c;要想支持发布sqlserver的空间表到geoserver就需要添加插件 1&#xff0c;下载插件 官网下载地址&#xff1a;https://geoserver.org/download/ 根据自己的版本下载指定的插件…

Java之并发编程(三)

五、Java 常见并发容器总结 1.ConcurrentHashMap ConcurrentHashMap : 线程安全的 HashMap 1.1 Collections.synchronizedMap() 并发时使用它方法包装HashMap同步&#xff0c;这属于全局锁&#xff0c;性能低下。 1.2 ConcurrentHashMap&#xff0c; 读写操作都能保证很高…

文献阅读-Deep multi-view learning methods: A review

文献阅读-Deep multi-view learning methods: A reviewAbstract1-Introduction1.1 Comparison with Previous Reviews2 Multi-view Learning Methods in The Deep Learning Scope2.1 Multi-view convolutional neural network2.2. Multi-view auto-encoder2.3. Multi-view gene…

杉数求解器

目录前言一、简介以及安装二、COPT交互式命令行工具2-1、普通工具命令2-2、COPT工具命令三、使用示例3-1、交互模式3-2、Windows下终端窗口直接加载四、Python接口4-1、安装4-2、案例分析五、COPT调优工具5-1、介绍5-2、调优工具相关参数六、Python API参考6-1、COPT常数类总结…

【Jetson安装Nomachine】

0. 介绍 Nomachine是一款免费的远程桌面访问应用程序。支持用户从任何地方访问连接到Internet的计算机。该应用程序允许多个用户访问单个PC&#xff0c;且支持使用不同的操作系统。 官网链接&#xff1a;NoMachine - Free Remote Desktop for Everybody 1. 下载Nomachine 软…

【C++】简单理解内联函数

内联函数1.内联函数的概念2.C为什么要有内联函数&#xff1f;3.内联函数展示3.1查看方式3.2 观察汇编代码4.使用内联函数的注意事项5.内联函数缺点和优点1.内联函数的概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有…

九龙证券|沪指收获2010年以来最强1月 北向资金净买入额刷新历史纪录

昨日&#xff0c;A股小幅调整&#xff0c;2023年1月行情随之收官。全体来看&#xff0c;1月A股商场拾级而上&#xff0c;盘面出现普涨格局&#xff0c;价值与生长风格均有亮眼体现。三大股指中&#xff0c;上证指数1月上涨5.39%&#xff0c;创2010年以来最佳局面。深证成指、创…

zookeeper 源码分享二 ----启动加载数据

单机zookeeper 启动加载数据 读取磁盘中快照文件&#xff0c;选择其中第一个能正确加载的文件&#xff0c;最多加载100个快照文件。反序列化快照文件&#xff0c;进行内存DataTree数据加载根据最新事物日志&#xff0c;加载事物日志快照并进行反序列化重新执行事物日志中的操作…

OAuth2流程演示示例

目录一、OAuth2流程演示示例1、创建项目结构①客户②认证服务器③资源拥有者④资源服务器2、流程①资源所有者②客户③客户④认证服务器⑤客户⑥资源服务器一、OAuth2流程演示示例 client 客户 authorization-server 认证服务 resource-owner 资源所有者 resource-server 资源服…

anaconda下载安装,镜像源配置修改及虚拟环境的创建

anaconda安装Anaconda 简介Anaconda 安装1.安装流程2.anaconda 配置修改3. 创建虚拟环境4.常用命令Anaconda 简介 Anaconda&#xff08;官方网站&#xff09;就是可以便捷获取包且对包能够进行管理&#xff0c;同时对环境可以统一管理的发行版本。Anaconda包含了conda、Python…

Cocos Creator游戏项目环境搭建和启动

背景获得了一套cocos creator2.4.2编写的游戏源码&#xff0c;需要在本地启动&#xff0c;查看一下是否符合预期要求。所以需要在本地搭建Cocos Creator环境&#xff0c;因为以前没有接触过&#xff0c;经过一番搜索&#xff0c;终于将环境搭建完成&#xff0c;为了备忘&#x…

【Sciter】Sciter 结合 Preact 封装 图片查看器总结

使用 react 结合 sciter 封装 图片查看器 组件 # 效果图 1、图片:宽度大于高度 2、图片:宽度小于高度 # 如何使用 <div class="container"></div

录音软件哪个好?分享两款免费实用的录音软件

有时候我们需要一款录音软件&#xff0c;来录制电脑内部的声音或者电脑外部的声音。比如录制网上无法下载的音乐、录制自己唱歌的声音、录制音频会议等等。那有没有既实用并且试用版就能录音软件呢&#xff1f;当然有&#xff01;小编今天就给大家介绍两款高性价比的录音软件&a…

Nhanes临床数据库挖掘教程2—非正态数据的基线表绘制(2)

美国国家健康与营养调查&#xff08; NHANES, National Health and Nutrition Examination Survey&#xff09;是一项基于人群的横断面调查&#xff0c;旨在收集有关美国家庭人口健康和营养的信息。 地址为&#xff1a;https://wwwn.cdc.gov/nchs/nhanes/Default.aspx 既往我们…

VUE + .NET CORE (.net6)基于asp.net 智能仓储快递物流系统源码

一、源码描述 这是一款简洁十分美观的ASP.NETsqlserver源码&#xff0c;前端vue,框架.netcore,mvc三层架构界面十分美观&#xff0c;功能也比较全面 二、功能介绍 该源码功能十分的全面&#xff0c;具体介绍如下&#xff1a; 用户待取包裹信息可以由快递网点员直接在选择用户…

学习记录 2023/02/01

一、学习内容&#xff1a; 1、OSEK网络管理规范基础&#xff08;CAN_NM报文格式、节点跳过判断机制、网络管理策&#xff09;; 2、UDS诊断服务回顾&#xff08;功能寻址与PHY&#xff0c;CAN升级工具的使用&#xff09;&#xff1b; 二、回顾提升 1、CAN程序升级工具使用(适用…

Linux内核panic核心执行逻辑

什么是OOPSOops是美国人比较常有的口语。就是有点意外&#xff0c;吃惊&#xff0c;或突然的意思。“oops”并不是很严重.对于linux内核来说&#xff0c;Oops就意外着内核出了异常&#xff0c;此时会将产生异常时出错原因&#xff0c;CPU的状态&#xff0c;出错的指令地址、数据…

实训六:启动过程和运行级别

实训六&#xff1a;启动过程和运行级别 2017 年 4 月 16 日 今日公布 实训目标 完成本次实训&#xff0c;将能够&#xff1a; 运用Shell命令管理进程。 在图形界面下管理进程。 配置cron调度。 实训准备 一台安装RHEL6系统的计算机&#xff0c;该系统除了root账户外&…