2017-06-12 157 views
0

我正在尝试实现Prime NG的选项卡视图组件。但我的标签本质上是动态的,即。 因此,当容器被加载时,它会发送多个AJAX请求,用于组件内部的数据(也许该组件被多次初始化?) 另一件事,在一个组件中,移动鼠标会在控制台上产生成千上万的错误。Angular 2中的动态组件

ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed 

ERROR CONTEXT [object Object] 

不知道为什么。在另一个地方使用相同的组件,并没有问题。

即使我删除了组件的动态特性,只需要放置4个静态标签,一切都可以正常工作(现在,同样的4个组件来自服务器)。

HTML模板:

<div class="col-md-12 padding0"> 
    <div class="tabViewWrapper"> 
    <p-tabView (onChange)="handleChange($event)"> 
     <p-tabPanel header="{{tab.tabName}}" *ngFor="let tab of tabs" > 
     <dynamic-component [componentData]="componentData"></dynamic-component> 
     </p-tabPanel> 
    </p-tabView> 
    <div> 
</div> 

组件:

@Component({ 
    selector: 'tab-view', 
    templateUrl: './tab-view.component.html', 
    styleUrls: ['./tab-view.component.scss'], 
    encapsulation: ViewEncapsulation.None, 
    entryComponents: [GenericDataTableComponent, SingleEditCategoryExplorerComponent, AssetsDataTableComponent] 
}) 
export class TabViewComponent implements OnInit { 
    private ngUnsubscribe: Subject<void> = new Subject<void>(); 
    private componentData = null; 
    private tabs: Array<any>; 
    private index:number; 
    private disabledTabs:Array<any>; 
    private disabledTabsWhenMetaDataClicked:Array<any>; 

    versionConfig = { 
    url: AppSettingProperties.DATA_TABLE_VALUES.VERSIONS_URL, 
    dateLocale: AppSettingProperties.DATA_TABLE_VALUES.LOCALE, 
    header: AppSettingProperties.DATA_TABLE_VALUES.VERSIONS_HEADER 
    }; 

    relatedConfig = { 
    url: AppSettingProperties.BASEURL + AppSettingProperties.DATA_TABLE_VALUES.RELATED_ENDPOINT, 
    header: AppSettingProperties.DATA_TABLE_VALUES.RELATED_HEADER 
    }; 

    constructor(private assetDataLoadedService: AssetDataLoadedService, private assetDetailsService: AssetDetailsService, private assetDetailDataModel:AssetDetailDataModel) { } 

    @ViewChildren(DynamicContainerComponent) dynamicContainers: QueryList<DynamicContainerComponent>; 

    ngOnInit() { 
    this.disabledTabs = []; 

    //Set items to be disabled when Metadata button is clicked 
    this.disabledTabsWhenMetaDataClicked = [AppSettingProperties.TAB_RELATEDITEMS, AppSettingProperties.TAB_VERSIONS]; 

    //Disable the tabs as per the condistions 
    this.disableTabsAsPerRequirement(); 

    //Assigning tabs 
    this.tabs = this.assetDetailsService.systemTabs; 

    } 
    getInitialSelected(tab){ 
    return this.selectedTab == this.tabs.indexOf(tab); 
    } 

    get selectedTab():number{ 
    return this.index; 
    } 

    set selectedTab(val:number){ 
    this.index = val; 
    var defaultTab = this.tabs[this.index]['tabName']; 

    if(!this.assetDetailDataModel.catalogId){ 
     this.assetDataLoadedService.assetDetailPublisher.subscribe(data=>{ 
     this.loadComponentByTab(defaultTab); 
     this.ngUnsubscribe.next(); 
     this.ngUnsubscribe.complete(); 
     }); 
    } 
    else{ 
     this.loadComponentByTab(defaultTab); 
    } 
    } 

    handleChange(e) { 
    let tabName: string = e.originalEvent.currentTarget.innerText; 
    this.selectedTab = e.index; 
    //this.loadComponentByTab(tabName);  
    } 

    loadComponentByTab(tabName:string){ 
    switch (tabName) { 
     case AppSettingProperties.TAB_METADATA: 
     this.componentData = { component: AssetsDataTableComponent, inputs: {} } 
     break; 
     case AppSettingProperties.TAB_CATEGORY: 
     let categoryConfig: object = {"catalog_id":this.assetDetailDataModel.catalogId,"item_id":this.assetDetailDataModel.assetId}; 
     console.log(categoryConfig); 
     this.componentData = { component: SingleEditCategoryExplorerComponent, inputs: { tabConfig: categoryConfig } } 
     break; 
     case AppSettingProperties.TAB_RELATEDITEMS: 
     this.componentData = { component: GenericDataTableComponent, inputs: { tabConfig: this.relatedConfig } } 
     break; 
     case AppSettingProperties.TAB_VERSIONS: 
     this.componentData = { component: GenericDataTableComponent, inputs: { tabConfig: this.versionConfig } } 
     break; 
    } 
    } 
} 

动态组件:

import { Component, Input, ViewContainerRef, ViewChild, ReflectiveInjector, ComponentFactoryResolver } from '@angular/core'; 

@Component({ 
    selector: 'dynamic-component', 

    template: `<div #dynamicComponentContainer></div>`, 
}) 
export class DynamicComponent { 
    private currentComponent = null; 

    @ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef; 

    constructor(private resolver: ComponentFactoryResolver) { } 

    // component: Class for the component you want to create 
    // inputs: An object with key/value pairs mapped to input name/input value 
    @Input() set componentData(data: { component: any, inputs: any }) { 
    console.log("Building Component Start"); 
    if (!data) { 
     return; 
    } 

    // Inputs need to be in the following format to be resolved properly 
    let inputProviders = Object.keys(data.inputs).map((inputName) => { return { provide: inputName, useValue: data.inputs[inputName] }; }); 
    let resolvedInputs = ReflectiveInjector.resolve(inputProviders); 

    // We create an injector out of the data we want to pass down and this components injector 
    let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicComponentContainer.parentInjector); 

    // We create a factory out of the component we want to create 
    let factory = this.resolver.resolveComponentFactory(data.component); 

    // We create the component using the factory and the injector 
    let component = factory.create(injector); 

    // We insert the component into the dom container 
    this.dynamicComponentContainer.insert(component.hostView); 

    // We can destroy the old component is we like by calling destroy 
    if (this.currentComponent) { 
     this.currentComponent.destroy(); 
    } 

    this.currentComponent = component; 
    console.log("Building Component Finish"); 
    } 
} 

另一件事是,在动态成分控制台开始被示出8倍。 控制台完成显示4-5次。

似乎真的很奇怪的行为。

+1

大概'this.assetDetailsS​​ervice.systemTabs'没有返回的数组。 – echonax

+0

您是否尝试过创建一个具有属性tabName的Tab对象?然后你会有'私人标签:数组;' – petre

回答

0

@echonax在评论中写道。

这是因为您试图迭代非数组的东西。
最有可能this.tabs

你可以尝试在一个div写出来的,而不是{{tabs|json}}*ngFor

+0

其数组。 [对象的对象],[对象的对象],[对象的对象],[对象的对象] [ 0:{ [功能]:, __proto__:{}, ID:0, TABNAME: “元数据” }, 1:{ [功能]:, __proto__:{}, ID:1, TABNAME: “类别” }, 2:{ [功能]:, __proto__:{}, 标识:2, tabName:“Related Items” }, 3:{ [功能]:, __proto__:{}, ID:3, TABNAME: “版本” }, 长度:4 ] –

+0

请更新与新的信息您的问题(数据,并正确格式化)。因为你粘贴的东西几乎没有意义 –

0

因为你的反应有时需要加载您的DOM将有tabs变量为未定义数组。

为了解决这个变量初始化为空数组如下

tabs:Array<any> = [] 

或在构造函数中作为

constructor(){ 
    this.tabs = []; 
}