Javascript 如何基于对象的属性加载动态组件?

Javascript 如何基于对象的属性加载动态组件?,javascript,angular,typescript,single-page-application,angular8,Javascript,Angular,Typescript,Single Page Application,Angular8,我试图建立一个卡片列表,其中可能包含不同的组件;例如,我有以下对象数组: { title: 'Title', descrption: 'Description', template: 'table', }, { title: 'Title', descrption: 'Description', template: 'chart', } 我从一个服务得到这个数组作为响应,然后我需要根据template属性将这些对象中的每一个匹配到一个组件,因此,例如,第一个项目应

我试图建立一个卡片列表,其中可能包含不同的组件;例如,我有以下对象数组:

{
   title: 'Title',
   descrption: 'Description',
   template: 'table',
},
{
  title: 'Title',
  descrption: 'Description',
  template: 'chart',
}
我从一个服务得到这个数组作为响应,然后我需要根据
template
属性将这些对象中的每一个匹配到一个组件,因此,例如,第一个项目应该匹配到
TableComponent
,第二个项目应该匹配到
ChartComponent

我正试图遵循有关角度的文档,但我不确定如何告诉该方法如何将数组中的每个对象与特定组件匹配

在我的父组件中,我创建了一个锚点,组件应在其中加载指令:

<ng-template appCheckpointHost></ng-template>
该示例显示了一个场景,“服务”每三秒运行一次,获取一个随机项,并显示它;但是我要做的是在父组件加载时获取所有项,并使用其各自的组件呈现每个项

有什么办法可以让它工作吗?

你可以查看我的博客

首先,我需要创建一个指令来引用视图中的模板实例

import { Directive, ViewContainerRef } from "@angular/core";

@Directive({
    selector: "[dynamic-ref]"
})
export class DynamicDirective {
    constructor(public viewContainerRef: ViewContainerRef) {}
}
然后我们简单地将指令放在视图中,如下所示

 <ng-template dynamic-ref></ng-template>
@ViewChild(DynamicDirective) dynamic: DynamicDirective;

constructor(
        private componentFactoryService: ComponentFactoryService
    ) {

    }

ngOnInit(){
       const dynamiCreateComponent = this.componentFactoryService.createComponent(TestComponent, this.dynamic);
       (<TestComponent>dynamiCreateComponent.instance).data = 1;
       (<TestComponent>dynamiCreateComponent.instance).eventOutput.subscribe(x => console.log(x));
}

ngOnDestroy(){
  this.componentFactoryService.destroyComponent();
}

/////////////////////////////////
export class TestComponent {
  @Input() data;
  @Output() eventOutput: EventEmitter<any> = new EventEmitter<any>();

  onBtnClick() {
    this.eventOutput.emit("Button is click");
  }      
}

我们将指令dynamic ref放在ng content中,这样我们就可以让Angular知道组件将在哪里渲染

接下来,我将创建一个服务来生成组件并销毁它

import {
    ComponentFactoryResolver,
    Injectable,
    ComponentRef
} from "@angular/core";
@Injectable()
export class ComponentFactoryService {
    private componentRef: ComponentRef<any>;
    constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

    createComponent(
        componentInstance: any,
        viewContainer: any
    ): ComponentRef<any> {
        const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
            componentInstance
        );
        const viewContainerRef = viewContainer.viewContainerRef;
        viewContainerRef.clear();
        this.componentRef = viewContainerRef.createComponent(componentFactory);
        return this.componentRef;
    }

    destroyComponent() {
        if (this.componentRef) {
            this.componentRef.destroy();
        }
    }
}
导入{
组件工厂分解器,
可注射,
成分参考
}从“@角度/核心”;
@可注射()
导出类ComponentFactoryService{
私有componentRef:componentRef;
构造函数(专用componentFactoryResolver:componentFactoryResolver){}
创建组件(
组件状态:任意,
viewContainer:任何
):ComponentRef{
const componentFactory=this.componentFactoryResolver.resolveComponentFactory(
分量恒量
);
const viewContainerRef=viewContainer.viewContainerRef;
viewContainerRef.clear();
this.componentRef=viewContainerRef.createComponent(componentFactory);
返回此.componentRef;
}
销毁组件(){
if(this.componentRef){
this.componentRef.destroy();
}
}
}
最后,在我们的组件中,我们可以这样调用服务

 <ng-template dynamic-ref></ng-template>
@ViewChild(DynamicDirective) dynamic: DynamicDirective;

constructor(
        private componentFactoryService: ComponentFactoryService
    ) {

    }

ngOnInit(){
       const dynamiCreateComponent = this.componentFactoryService.createComponent(TestComponent, this.dynamic);
       (<TestComponent>dynamiCreateComponent.instance).data = 1;
       (<TestComponent>dynamiCreateComponent.instance).eventOutput.subscribe(x => console.log(x));
}

ngOnDestroy(){
  this.componentFactoryService.destroyComponent();
}

/////////////////////////////////
export class TestComponent {
  @Input() data;
  @Output() eventOutput: EventEmitter<any> = new EventEmitter<any>();

  onBtnClick() {
    this.eventOutput.emit("Button is click");
  }      
}
@ViewChild(DynamicDirective)DynamicDirective:DynamicDirective;
建造师(
私有componentFactoryService:componentFactoryService
) {
}
恩戈尼尼特(){
const dynamiccreatecomponent=this.componentFactoryService.createComponent(TestComponent,this.dynamic);
(dynamicCreateComponent.instance).data=1;
(dynamiCreateComponent.instance).eventOutput.subscribe(x=>console.log(x));
}
恩贡德斯特罗(){
this.componentFactoryService.destroyComponent();
}
/////////////////////////////////
导出类TestComponent{
@输入()数据;
@Output()eventOutput:EventEmitter=neweventemitter();
onBtnClick(){
this.eventOutput.emit(“按钮为单击”);
}      
}

您可以创建如下词典:

const nameToComponentMap = {
  table: TableComponent,
  chart: ChartComponent 
};
然后,只需使用此字典,根据items数组中特定
模板
属性来确定应该呈现哪个组件:

const componentTypeToRender = nameToComponentMap[item.template];
this.componentFactoryResolver.resolveComponentFactory(componentTypeToRender);

可以使用ngSwitch()根据模板渲染组件value@ajaiJothi是的,我有点想避开ngSwitch;我不知道,但感觉使用动态加载更有效?虽然可能是错误的,但不知道这两种方法的优点/缺点您需要在模板或ts文件中使用switch语句(如果您使用的是componentFactory)-因为您需要将组件引用传递给
resolveComponentFactory
。我看不到一种基于字符串值动态定位组件的方法,这个字符串值看起来很不错,而且对于多个组件来说,因为它是一个大数组,所以我应该只放置
this.componentFactoryResolver.resolveComponentFactory(componentTypeToRender)
forEach
循环中?听起来对我来说是最明显的方式是的,这里没有什么难事。您只需在数组上循环并传递专用类型,具体取决于
项;我的坏习惯是过度复杂的东西,非常感谢,这似乎很容易处理。我如何修改它以允许同时呈现多个不同的组件?根据我所看到的,我想它应该是关于
ngOnInit()
中的代码,可能是为数组中的每个元素运行这些行?