通过模拟数据实现Angular动态表单和数据库本文对之前的实现做了一些修改。例如,不使用[ngSwitch],而是创建自定义组件配置类,然后使用动态组件渲染组件,对修改关闭,对扩展开放。发展原则相近。具体可以查看源码,文末已经给出。在此基础上,本文将结合数据表结构和模拟数据,简单演示以教师新建应用和编辑应用为场景,如何将数据库中的数据转化为v-layer渲染。出形式。最终效果看起来类似于普通表单,实际上每个表单都是动态呈现的。一、修改说明本文中使用的类名和属性名与Angular动态表单构建简单实现中的有所不同,这里简单说明一下。本文中的表单对象模型将使用FormInfo作为类名,动态表单模板将使用FormComponent作为类名,动态表单内容即表单项将使用FieldComponent作为类名。更改名称的Angular动态表单构造的简单实现);本文演示从后台获取原始数据,然后将原始数据转换成FormInfo,再通过FormInfos获取对应的表单。所以我们要解决的主要问题是:理解ER图是如何将原始数据转换成FormInfo对象模型的3.ER图模型实现基本功能的动态表单的实体图如下,请有实体图的一般理解。4.ER图的含义4.1.表格构造首先,让我们讨论一下ER图的结构。这个ER图中有8个表。暂时只讨论应用类型ApplyType、字段Field、字段类型FieldType三张表。申请类型:对申请进行分类,如获奖申请、参赛申请等。字段:数据库中记录的表单字段,如表单中的姓名输入、地址输入等。字段类型:字段对应的自定义类型。比如name应该是输入文本,那么可以使用textbox作为type属性的值;address可以是selection类型,即dropdown是value(上文定义的两种类型)。每个应用类型对应多个字段,每个字段关联一个字段类型。它们之间的关系是,一个应用类型就是一个表单,对应多个表单项(即字段),表单项的表单由表单类型指定。4.2.表单值记录讨论申请表单Apply和字段记录表单FieldRecord。以上为新增内容。添加完成后需要保存数据,申请表Apply对应添加完成后保存的申请,通过字段记录表FieldRecord记录其值。就像申请类型表ApplyType和字段表Field的关系一样,申请表Apply和字段表Field的关系也是一样的,只是中间增加了一个记录值的中间表。4.3.表单验证规则继续讨论字段验证器FieldValidator,它记录了每个字段的验证规则,每个字段可能关联多个验证规则,比如required、unique。因为要考虑字段对验证器的要求和用户的输入,所以在自定义表单时,需要指定验证器的范围,用户不能随意选择验证器。因此需要先通过字段类型表ApplyType到字段校验器表FieldValidator中获取可选的校验器,再由用户进一步选择,最终实现不同的字段有不同的校验规则。4.4.字段选项最后添加数据集和数据项两张表。两个表之间的关系非常简单。每个数据集对应多个数据项。主要原因是这两个表存在的原因。有一些字段类型需要选择,所以给出选项,比如select和radio等,这时候两个表就可以发挥作用了。对于一些静态数据,比如性别(男、女)、评分(A、B、C)等,可以使用数据集来提供。对于需要实时渲染的动态数据(比如学生选课、班级选课),可能需要自定义相应的组件。至于为什么数据集DataSet关联的是字段表Field,而不是字段类型表FieldType,认为如果需要添加更多的数据集,需要创建更多的自定义组件与后者建立关联,而如果使用前者,则不需要补充组件来建立关系。5.将原始数据转换为FormInfo本文中使用的数据都是预先定义好的模拟数据。新建demo先准备好相应的模拟数据';从'../entity/data-set'导入{DataSet};从'../entity/data-item'导入{DataItem};从'../entity/apply-type'导入{ApplyType};从'../entity/field-validator'导入{FieldValidator};constMockDataItems=[{id:1,name:'male',weight:2,dataSet:{id:1}asDataSet},{id:2,name:'Female',weight:1,dataSet:{id:1}作为数据集},]作为数据项[];constMockDataSets=[{id:1,name:'Gender',dataItems:MockDataItems}]asDataSet[];constMockFieldValidators=[{id:1,name:'required',key:'required',value:true}]作为FieldValidator[];constMockFields=[{id:1,fieldType:{id:1,type:'textbox'},fieldValidators:MockFieldValidators,key:'name',label:'name',weight:4,type:'text'},{id:2,fieldType:{id:2,type:'textbox'},fieldValidators:MockFieldValidators,key:'username',label:'username',权重:3,类型:'text'},{id:3,fieldType:{id:3,类型:'textbox'},fieldValidators:MockFieldValidators,键:'email',标签:'email',权重:2,type:'email'},{id:4,fieldType:{id:4,type:'textbox'},fieldValidators:MockFieldValidators,key:'jobNumber',label:'jobnumber',weight:1,类型:'number'},{id:5,fieldType:{id:5,type:'radio'},fieldValidators:MockFieldValidators,key:'sex',label:'gender',数据集:MockDataSets[0],重量:0,type:''},]asField[];exportconstMockApplyType={id:1,name:'Teacher'snew',fields:MockFields}asApplyType;上面的例子定义了1个应用类型,5个字段,1个验证器和一个与男性和女性数据项相关联的数据集。从数据库中获取这些数据后,再转换成FormInfo。FormInfos中对象的个数取决于Fields的长度,即每个Field都会转化为一个FormInfo。下面是具体的转换方法:privategetFormInfo(field:Field,value?:any):FormInfo{constformInfo=newFormInfo({key:field.key,label:field.label,weight:field.weight,controlType:field.fieldType.type,type:field.type,rule:this.getRule(field.fieldValidators)asunknownasRuleType,value});如果(DynamicOptionControls.includes(field.fieldType.type)){formInfo.options=field.dataSet.dataItems.map((item)=>{return{value:item.id,label:item.name,weight:item.重量};});}返回表单信息;}FormInfo类中的controlType和type这两个属性分别表示自定义组件的类型和细分类型(如text,number);在该方法中,通过获取MockFieldValidators中各个对象的key和value来获取验证规则(rule)对象,在该方法中,还需要注意数据集的使用,即判断是否是对应的field.fieldType.type(即controlType)是需要通过预定义的数组来添加options的字段类型,如果需要,则数据集中的数据项会在这里填充,如果不需要则不填充需要。这样就可以得到对应的FormInfo数组了。至于如何渲染,之前的文章已经讲解过了,但是本文的实现会有些不同。比如自定义组件的选择就没有使用[ngSwitch],而是使用了动态组件。这里不再赘述,实现方法可以参考https://worktile.com/kb/p/6517。EDITDemo我们在mock数据中添加以下两项:constMockFieldRecords=[{id:1,apply:{id:1},field:MockFields[0],value:'张三'},{id:2,apply:{id:1},字段:MockFields[1],value:'zhangsan'},{id:3,apply:{id:1},字段:MockFields[2],value:'zhangsan@yunzhi.club'},{id:4,应用:{id:1},字段:MockFields[3],值:'0621211001'},{id:4,应用:{id:1},字段:MockFields[4],value:1},]asFieldRecord[];exportconstMockApply={id:1,applyType:{id:1,name:'teacherAdd'},status:0,fieldRecords:MockFieldRecords}asApply;edited和newAddition基本相同,只是编辑时获取的表单需要设置value的初始值,而这个初始值就是已经记录在FieldRecord表中的value属性的值,即MockFieldRecords中模拟数据。查看前面的方法可以发现,初始值是通过方法中的可选参数值来设置的。privategetFormInfo(field:Field,value?:any):FormInfo{constformInfo=newFormInfo({...,value});...}6.总结以上是当动态表单和数据库结合后,实现起来很简单。文中给出了大致思路,代码涉及较少。完整的示例代码可以参考:github:https://github.com/chshihang/dynamic-form-ergitee:https://gitee.com/chshihang/dynamic-form-er项目目录结构如下:├──app│├──app-routing.module.ts│├──app.component.html│├──app.component.ts│├──app.module.ts│├──动态表单││├──dynamic-form.module.ts││├──字段││││├──组件│││││├──控制类型列表。config.ts││││├──动态复选框││││││├──dynamic-checkbox.component.html││││││└──dynamic-checkbox.component.ts││││├─动态下拉│││││├──dynamic-dropdown.component.html│││││││└──dynamic-dropdown.component.ts││││├──动态错误││││├──dynamic-error.component.html│││││└──动态ic-error.component.ts││││├──动态无线电│││││├──dynamic-radio.component.html│││││└│──tdynamic-radio.component.│└──动态文本框││││├──dynamic-textbox.component.html││││└──动态文本框.component.ts│││├──field.component.html││├──field.component.html││──field.component.ts││└──form││├──form.component.html││└──form.component.ts│└──teacher│├──teacher-add││├──teacher-add.component.html││└──teacher-add.component.ts│├──teacher-edit││├──teacher-edit.component.html││└──teacher-edit.component.ts│├──teacher-index││├──teacher-index.component.html││└──teacher-index.component.ts│├──teacher-routing.module.ts│└──teacher.module。ts├──assets│└──mock-form-data.ts├──实体│├──apply-type.ts│├──apply.ts│├──data-item.ts│├──data-set.ts│├──field-record.ts│├──field-type.ts│├──field-validator.ts│├──field.ts│├──表单信息。ts│└──rule-type.ts├──environments│├──environment.prod.ts│└──environment.ts├──favicon.ico├──index.html├──interface│└──dynamic-form.interface.ts├──main.ts├──polyfills.ts├──service│└──dynamic-form.service.ts├──styles.scss└──test.ts