在我的angular(2)应用程序中,我的联系人有一个属性列表(字段)。每个属性都有自己的类型,如Date,Gender,String,Int等。
在联系人编辑器中,我根据字段的类型呈现特定的表单元素。日期选择器,性别广播组等。
为此,我现在对字段类型有一个(相当大的)switch语句,其中每个case都是一个特定的表单元素/组件。
<ng-container [formGroup]="formGroup" [ngSwitch]="field.fieldType">
<sp-contact-field-checkbox-list *ngSwitchCase="ContactFieldType.SET" [formControlName]="formControlName" [options]="field.options"></sp-contact-field-checkbox-list>
<div *ngSwitchCase="ContactFieldType.GENDER">
<sp-gender-input [id]="formControlName" [formControlName]="formControlName"></sp-gender-input>
</div>
...
在另一个组件中,我显示了联系人的详细信息视图。我有一个类似的开关案例,所以每个属性值都正确呈现。
我觉得在HTML中使用这些大型switch语句可能是反模式或糟糕的设计。添加/更改属性类型需要在多个文件中完成。
有没有人对这个问题有更好的(有角度的)解决方案?感觉应该有一个多态解决方案,但我不能用角度来做。
答案 0 :(得分:2)
我会给你一个解决方案,其中包含我当前项目的示例。我们在服务中移动开关并且dinamicaly创建内容。如果您的数据更改dinamicaly和html模板有非常不同的结构是一个很好的解决方案。否则,请考虑使用您的开关案例创建一个新组件。
所以, 首先,你需要一个容器。为了使用ViewContainerRef,您应该创建一个指令。
import {Directive, Input, ViewContainerRef} from '@angular/core';
@Directive({
selector: '[assignment-container]',
})
export class AssignmentContainer {
constructor(public viewContainerRef: ViewContainerRef) { }
}
提供管理dinamicaly创建组件的服务。
@Injectable()
export class AssignmentTemplateService {
constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
public initTemplate(assignmentTemplateContainer: AssignmentContainer, model: any, permissions: any) {
this.loadAssignmentTemplateComponent(assignmentTemplateContainer, model, permissions);
}
private loadAssignmentTemplateComponent(assignmentTemplateContainer:AssignmentContainer, model: any, permissions: any) {
let componentRef;
// put you switch cases
switch(model.linkedEntityType) {
default: {
componentRef = this.retrieveTemplateComponent(GeneralAssignmentTemplateComponent, assignmentTemplateContainer);
//Set the inputs
componentRef.requestTypeObject = model;
componentRef.permissions = permissions;
}
}
}
private retrieveTemplateComponent(componentType: Type<IAssignmentTemplateComponent>, assignmentTemplateContainer: AssignmentContainer) : IAssignmentTemplateComponent {
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentType);
//Clear the container content
let viewContainerRef = assignmentTemplateContainer.viewContainerRef;
viewContainerRef.clear();
//Get the component instance to set required fields like the model
return viewContainerRef.createComponent(componentFactory).instance;
}
}
对于每个开关案例,您应该创建一个不同的组件,如GeneralAssignmentTemplateComponent
在需要使用它的组件内部,您应该添加容器
<div assignment-container></div>
在.ts文件中,您应该添加对容器的引用。 //按类型选择 @ViewChild(AssignmentContainer)assignmentTemplateContainer;
添加服务实例。传递容器参考。
ngAfterViewInit() {
this.assignmentTemplateService.initTemplate(this.assignmentTemplateContainer, this.model, this.permissions);
}