我正在尝试实现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次。
似乎真的很奇怪的行为。
大概'this.assetDetailsService.systemTabs'没有返回的数组。 – echonax
您是否尝试过创建一个具有属性tabName的Tab对象?然后你会有'私人标签:数组;' –
petre