Angular - как создать отдельные контейнеры ViewContainerRef для разных вкладок в mat-tab
Я создаю модуль компонента времени выполнения с динамическим компонентом, привязывая к нему html-данные и функции, которые я извлекаю из вызова API, как строковые данные. И затем загрузка вновь созданного компонента в мой контейнер, помещенный во вкладки, так как я динамически создаю вкладки в соответствии с данными. Процесс работает для первой вкладки, но не для других вкладок.
Это может означать, что контейнер, куда я отправляю свой компонент времени выполнения, генерируется один раз, таким образом, не отражаясь для других вкладок.
HTML:
<mat-tab-group [selectedIndex]="tabIndex" (selectedTabChange)="getNewTabFields($event)">
<mat-tab *ngFor="let tab of tabs" [label]="tab.displayName">
<div *ngIf="errorOccured" class="text-align-center"> No Data Found! </div>
<ng-container #container></ng-container>
</mat-tab>
</mat-tab-group>
Составная часть:
@ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
ngOnInit() {
this.templateInitial =
this.searchConfig.configurations[0].value.resultView;
this.query = this.searchConfig.configurations[6].value.queryParams;
this.collectionName =
this.searchConfig.configurations[6].value.collectionName;
this.loadSearchData();
}
compileTemplate() {
const metadata = {
selector: `runtime-component`,
template: this.templateInitial
};
const _mydata = this.solrResponse.response.docs;
const code: string = this.searchConfig.configurations[1].value['logic'];
const result: string = ts.transpile(code);
const runnalbe: any = eval(result);
const compileClass = class RuntimeComponent {
solrResponses = _mydata;
presentLogic = runnalbe;
};
const factory = this.createComponentFactorySync(this.compiler, metadata, compileClass );
if (this.componentRef) {
this.container.remove(this.container.indexOf(this.componentRef));
this.componentRef = undefined;
}
this.componentRef = this.container.createComponent(factory);
}
private createComponentFactorySync(compiler: Compiler, metadata: Component, componentClass: any): ComponentFactory<any> {
const decoratedCmp = Component(metadata)(componentClass);
@NgModule({ imports: [CommonModule, SharedModule], declarations: [decoratedCmp] })
class RuntimeComponentModule { }
const module: ModuleWithComponentFactories<any> = compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);
this.componentInstance = module.componentFactories.find((f) => f.componentType === decoratedCmp);
return module.componentFactories.find((f) => f.componentType === decoratedCmp);
}
getNewTabFields(event) {
this.tabIndex = event.index;
this.constructTabData(this.tabIndex);
}
constructTabData(i) {
this.templateInitial = this.tabs[i].configurations.resultView;
this.query = this.tabs[i].configurations.query[0].queryParams;
this.collectionName = this.tabs[i].configurations.query[0].queryParams['collection'].split(' ')[0];
this.loadSearchData();
}
loadSearchData(_row = 10, _start = 0) {
this.solrSearchService.getSolrData(this.query, this.collectionName).subscribe((data: any) => {
this.solrResponse = [];
this.solrResponse = JSON.parse(data);
this.compileTemplate();
});
}
1 ответ
Я бы предпочел использовать для создания этих контейнеров директиву.
HTML:
<mat-tab-group [selectedIndex]="tabIndex" (selectedTabChange)="getNewTabFields($event)">
<div *ngIf="errorOccured" class="text-align-center"> No Data Found! </div>
<ng-container myDirective *ngFor="let tab of tabs" [tab]="tab"></ng-container>
</mat-tab-group>
Моя директива:
@Directive({
selector: '[myDirective]'
})
export class MyDirective implements OnInit {
@Input()
tab: MyTamComponent;
constructor(private resolver: ComponentFactoryResolver, private container: ViewContainerRef) {}
ngOnInit(): void {
const factory = this.resolver.resolveComponentFactory<MyTamComponent>(MyTamComponent);
const component = this.container.createComponent(factory);
// other stuff
component.instance.label = tab.displayName;
component.instance.ref = component;
}
}