前言
我的项目中须要实现一个模块,工作治理,这里的工作是多样的。比如说打疫苗是一个工作,咱们首先建设这个工作,而后在工作中规定几个字段,比如说打疫苗的地点,工夫,接种疫苗品牌等等。关爱老人是另一个工作,工作中也规定几个字段,何时去关爱老人,行为记录等。打疫苗工夫和关爱老人工夫须要用到工夫抉择组件,打疫苗地点个接种疫苗品牌须要用到列表抉择组件,行为记录须要用到文本输出组件。不同的字段须要用到不同的输出组件。
E-R图
一个工作对应多个表单项,一个表单项有一个表单类型。一个工作对应每一个居民生成一个工作详情,一个表单项和一个工作详情独特对应一个表单值。比如说打疫苗这是工作,打疫苗的工夫,打疫苗的地点是表单项,打疫苗的工夫(表单项)对应表单类型是工夫(表单类型),打疫苗的地点(表单项)对应表单类型是单向抉择(表单类型)。打疫苗这个工作对应张三(居民)生成张三打疫苗工作(工作详情),对应李四(居民)生成李四打疫苗工作(工作详情),张三打疫苗工作(工作详情)的打疫苗工夫(表单项)是2022年3月18日(表单值),李四打疫苗工作(工作详情)的打疫苗工夫(表单项)是2022年3月10日(表单值)。
动静表单
对于设置一个工作的多个表单项很简略,无非就是抉择一下表单项的表单类型,表单类型比方文本,工夫,单选,多选等。问题是如何依据表单类型显示不同的输出形式。比方表单类型是工夫就显示一个工夫选择器,表单类型是文本就显示一个输入框。当然咱们能够依据表单类型去进行判断,不同的表单类型显示不同组件,如下图。
然而这意味着如果咱们日后每新增一种表单类型,就要去减少一个if,也就是变动一次代码,这显然不是咱们想要的。
angular有动静表单的性能,帮忙咱们脱离繁冗的if判断(在减少一个新的表单类型时,动静表单也须要改变代码,比方新增一个表单类型对应组件)。
首先咱们须要定义一个指令,这个指令的作用是标记一个地位通知angular把组件插到什么中央。
@Directive({ selector: '[FormItem]',})export class FormDirective { constructor(public viewContainerRef: ViewContainerRef) { }}
而后咱们创立主页面组件v层
<p>form-detial works!</p><div class="ad-banner-example"> <h3>工作详情</h3> <ng-template FormItem></ng-template></div>
咱们将咱们定义的名叫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<FormComponent>(adItem.component); componentRef.instance.data = adItem.data; } }}
初始化时,先通过服务层获取表单项数组,而后循环遍历每一个表单项,最初通过viewContainerRef的createComponent()办法加载表单项类型对应组件。
对于不同的表单类型输出组件,咱们先规定一个公共父类接口。
export interface FormComponent { data: any;}
所有的表单类型输出组件继承这个接口,比如说单选表单类型
@Component({ selector: 'app-select', templateUrl: ' <p>{{data.text}}</p> <select class="custom-select" id="inputGroupSelect02"> <option *ngFor="let selection of data.selections" [value]="selection.value">{{selection.name}}</option> </select> ', styleUrls: ['./select.component.css']})export class SelectComponent implements OnInit, FormComponent { constructor() { } ngOnInit(): void { } @Input() data: any;}
文本表单类型
@Component({ selector: 'app-text', templateUrl: ' <p>{{data.text}}</p> <input type="text"> ', styleUrls: ['./text.component.css']})export class TextComponent implements OnInit, FormComponent { constructor() { } ngOnInit(): void { } @Input() data: any;}
最终成果