Как избежать переключения ng и генерировать компонент по типу

В настоящее время я получаю массив (в коде ниже resourceTypes) и с ngSwitch. Как вы можете видеть в зависимости от TypeName, я создаю различные виды компонентов / директив (config-resource-editor или mvc-resource-editor или...). Однако мне не нравится этот код, потому что когда я создаю больше редакторов ресурсов, мне всегда приходится модифицировать этот код и т. Д. Как я могу реорганизовать код, чтобы я мог просто создать правильный редактор ресурсов в зависимости от типа без ng-switch. Я посмотрел на ng-content, думаю, что с этим нужно что-то делать, но я не вижу этого.

TL; DR: Как я могу изменить код, приведенный ниже, чтобы мне больше не приходилось использовать ngSwitch, а "связывал" тип с компонентом.

 <div *ngFor="let aType of resourceTypes; let i = index" role="tabpanel" class="tab-pane" [ngClass]="{'active': i==0}" [attr.id]="aType.Name">
                <span *ngSwitch="aType.Name">
                    {{aType.Name}} tab content here
                    <config-resource-editor [application]="application" ngSwitchWhen="Config" template></config-resource-editor>
                    <mvc-resource-editor [application]="application" ngSwitchWhen="MVC" template></mvc-resource-editor>
                    <other-resource-editor [application]="application" ngSwitchWhen="Other" template></other-resource-editor>
                    <wcf-resource-editor [application]="application" ngSwitchWhen="WCF" template></wcf-resource-editor>
                    <web-resource-editor [application]="application" ngSwitchWhen="Web" template></web-resource-editor>
                    <webapi-resource-editor [application]="application" ngSwitchWhen="WebAPI" template></webapi-resource-editor>
                </span>
            </div>

Если что-то не понятно, не стесняйтесь спрашивать.

заранее спасибо

1 ответ

Вы можете создать компонент-оболочку и использовать @ViewChild, чтобы избавиться от случая переключения.

Ваша обертка будет выглядеть примерно так:

@Component({
    selector: 'my-wrapper',
    template: `<div #target></div>`
})
export class MyWrapper {
    @ViewChild('target', {read: ViewContainerRef}) target;
    cmpRef: ComponentRef<Component>;
    currentComponent: Component;
    private isViewInitialized: boolean = false;
    constructor(
            private componentFactoryResolver: ComponentFactoryResolver,
            private cdRef: ChangeDetectorRef,
            private wrapperService: WrapperService
    ){}

    updateComponent() {
        if (!this.currentComponent) {
            return;
        }
        if (!this.isViewInitialized) {
            return;
        }
        if (this.cmpRef) {
            this.cmpRef.destroy();
        }
        let factory = this.componentFactoryResolver.resolveComponentFactory(this.currentComponent);
        this.cmpRef = this.target.createComponent(factory);
    }

    ngAfterViewInit() {
        this.cdRef.detectChanges();
        this.isViewInitialized = true;
        this.currentComponentSubscription = this.wrapperService.getCurrentComponent().subscribe(c => {
            this.currentComponent = c;
            if (c) {
                this.updateComponent();
            }
        });
    }

    ngOnDestroy() {
        if (this.cmpRef) {
            this.cmpRef.destroy();
        }
        if(this.currentComponentSubscription){
           this.currentComponentSubscription.unsubscribe()
        }
    }
}

Создайте WrapperService и напишите метод получения / установки для текущего компонента и обратите внимание, что метод получения должен возвращать объект BehaviorSubject:

private _currentComponent: BehaviorSubject<Component> = new BehaviorSubject(null);
getCurrentComponent(): BehaviorSubject<Component> {
    return this._currentComponent;
}

setCurrentComponent(value: Component) {
   this._currentComponent.next(value);
}

Используйте селектор для компонента MyWrapper вместо вашего ngSwitch и установите текущий компонент, используя службу оболочки в родительском компоненте, где определен resourceTypes.

Вам также необходимо добавить компоненты, присоединяемые / отключаемые к entryComponents в @NgModules:

@NgModule({
    entryComponents: <array of components>
})

Примечание. При настройке _currentComponent необходимо указать ссылку на компонент, а не строку.

Кредиты: @Gunter Я также сослался на его пример, чтобы это пошло для меня.

Другие вопросы по тегам