前言
项目中需要实现一个模块,任务管理,这里的任务是多样的。比如说打疫苗是一个任务,我们首先建立这个任务,然后在任务中规定几个字段,比如说打疫苗的地点,时间,接种疫苗品牌等等。关爱老人是另一个任务,任务中也规定几个字段,何时去关爱老人,行为记录等。打疫苗时间和关爱老人时间需要用到时间选择组件,打疫苗地点个接种疫苗品牌需要用到列表选择组件,行为记录需要用到文本输入组件。不同的字段需要用到不同的输入组件。
E-R图
文章图片
一个任务对应多个表单项,一个表单项有一个表单类型。一个任务对应每一个居民生成一个任务详情,一个表单项和一个任务详情共同对应一个表单值。比如说打疫苗这是任务,打疫苗的时间,打疫苗的地点是表单项,打疫苗的时间(表单项)对应表单类型是时间(表单类型),打疫苗的地点(表单项)对应表单类型是单向选择(表单类型)。打疫苗这个任务对应张三(居民)生成张三打疫苗任务(任务详情),对应李四(居民)生成李四打疫苗任务(任务详情),张三打疫苗任务(任务详情)的打疫苗时间(表单项)是2022年3月18日(表单值),李四打疫苗任务(任务详情)的打疫苗时间(表单项)是2022年3月10日(表单值)。
动态表单
对于设置一个任务的多个表单项很简单,无非就是选择一下表单项的表单类型,表单类型比如文本,时间,单选,多选等。问题是如何根据表单类型显示不同的输入方式。比如表单类型是时间就显示一个时间选择器,表单类型是文本就显示一个输入框。当然我们可以根据表单类型去进行判断,不同的表单类型显示不同组件,如下图。
文章图片
但是这意味着如果我们日后每新增一种表单类型,就要去增加一个if,也就是变动一次代码,这显然不是我们想要的。
angular有动态表单的功能,帮助我们脱离繁杂的if判断(在增加一个新的表单类型时,动态表单也需要改动代码,比如新增一个表单类型对应组件)。
首先我们需要定义一个指令,这个指令的作用是标记一个位置告诉angular把组件插到什么地方。
@Directive({
selector: '[FormItem]',
})
export class FormDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
然后我们创建主页面组件v层
form-detial works!
任务详情
我们将我们定义的名叫FormItem指令放入到ng-template标签中,ng-template是一个空白容器,不会有任何的负作用。
主页面c层
export class IndexComponent implements OnInit, OnDestroy {formItems: FormItem[] = [];
@ViewChild(FormDirective, {static: true}) adHost!: FormDirective;
interval: number|undefined;
constructor(private formService: FormService) {}ngOnInit() {
this.formItems = this.formService.getFormData();
this.loadComponent();
}ngOnDestroy() {
clearInterval(this.interval);
}loadComponent() {
for (var i = 0;
i < this.formItems.length;
i++) {
const adItem = this.formItems[i];
const viewContainerRef = this.adHost.viewContainerRef;
const componentRef = viewContainerRef.createComponent(adItem.component);
componentRef.instance.data = https://www.it610.com/article/adItem.data;
}
}
}
初始化时,先通过服务层获取表单项数组,然后循环遍历每一个表单项,最后通过viewContainerRef的createComponent()方法加载表单项类型对应组件。
对于不同的表单类型输入组件,我们先规定一个公共父类接口。
export interface FormComponent {
data: any;
}
所有的表单类型输入组件继承这个接口,比如说单选表单类型
@Component({
selector: 'app-select',
templateUrl: '{{data.text}}
',
styleUrls: ['./select.component.css']
})
export class SelectComponent implements OnInit, FormComponent {constructor() { }ngOnInit(): void {
}@Input() data: any;
}
文本表单类型
@Component({
selector: 'app-text',
templateUrl: '{{data.text}}
',
styleUrls: ['./text.component.css']
})
export class TextComponent implements OnInit, FormComponent {constructor() { }ngOnInit(): void {
}@Input() data: any;
}
【angular动态表单】最终效果
文章图片
推荐阅读
- 前端|Angular
- web面试题|angular常见面试题及答案
- vue|发布angular指令,vue指令,js文件到npm的流程
- 前端WEB学习|JavaScript框架有哪些(JS框架汇总)
- Angular实现的增删改查
- angular版本更新与配置文件问题
- 登录的实现
- ng : 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\ng.ps1,因为在此系统上禁止运行脚本。
- Angular 变化检测详解