重构大(ng)Switch语句

时间:2018-04-18 07:21:08

标签: angular

在我的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语句可能是反模式或糟糕的设计。添加/更改属性类型需要在多个文件中完成。

有没有人对这个问题有更好的(有角度的)解决方案?感觉应该有一个多态解决方案,但我不能用角度来做。

1 个答案:

答案 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);
    }