Reputation: 5927
I am trying to create the global component, so other developers can use this component to their project.
Here the aim is, I have my local component called app.component.ts and it has one child component. And I have bundled the global component and kept inside the node_modules folder.
app.component.html
<p-table #dt [value]='genes' [columns]="tableHeader" dataKey="geneName">
<ng-template pTemplate="header">
<th></th>
<th>Gene</th>
<th>Position</th>
<th>Value</th>
</ng-template>
<ng-template pTemplate="body" let-columns="columns" let-expanded="expanded" let-gene>
<tr [pSelectableRow]="gene">
...
</tr>
</ng-template>
<ng-template pTemplate="rowexpansion" let-rowData let-columns="columns">
<tr>
<gene-child [geneData]="rowData" (geneSelection)="selection()"> </gene-child>
</tr>
</ng-template>
</p-table>
child.component.ts
import { ConfirmationService } from 'primeng/api';
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'gene-child',
templateUrl: './gene.html',
})
export class GeneChildComponent implements OnInit {
@Input() geneName: any;
@Output() geneSelection = new EventEmitter();
Above code is working fine without any issue.
Now I am creating the global component to handle the priemng table, from the parent component just I need to pass the headers and data.
updated code
app.component.html
<bio-tables [tableData]="genes" [header]="tableHeader"></bio-tables>
above code also working fine.
But here my problem is I need to pass the "selector" gene-child
to the global component so I did the following, but it is giving the error,
<bio-tables [tableData]="genes" [header]="tableHeader" [rowExpansionSelector]="gene-child"></bio-tables>
I tried to storing the gene-child component into one variable and tried passing it, like below code
app.component.ts
import { GeneChildComponent } from './gene-child.component.ts';
...
export class ....{
geneChlid = GeneChildComponent;
app.component.html
<bio-tables [tableData]="genes" [header]="tableHeader" [rowExpansionSelector]="geneChild"></bio-tables>
above code also not working. I am not sure how to pass the selector to the child component.
Upvotes: 1
Views: 2649
Reputation: 782
From what i understood, you want to pass a dynamic component to your bio-tables
component, if is that so, you could try do the following:
Create and abstract class let´s call it GenericChild
in here define what do you expect from component.
export abstract class GenericChild {
abstract geneName: any;
abstract geneSelection: EventEmitter<any>;
}
Make the GeneChildComponent
or whatever component you want, to extends from this abstract class.
export class GeneChildComponent extends GenericChild {
@Input() geneName: any;
@Output() geneSelection = new EventEmitter<any>();
}
We will create a wrapper component so we can access to let-rowData
, this wrapper will create a child component (GeneChildComponent
that is the dynamic component). For this we need a ng-contaier
as ViewContainerRef
and also we will extend from GenericChild.
To create the component we will use ComponentFactoryResolver
.
The template:
<ng-container #child></ng-container>
The component:
export class ChildWrapper extends GenericChild {
@Input()
genericChild: Type<GenericChild>;
@Input()
geneData: any;
@Output()
geneSelection: EventEmitter<any> = new EventEmitter<any>();
@ViewChild("child", { read: ViewContainerRef })
childsContainer: ViewContainerRef;
constructor(
private factory: ComponentFactoryResolver,
private cdr: ChangeDetectorRef
) {
super();
}
//create the component in the container, and set the values of the instance.
ngAfterViewInit(): void {
const componentFactory = this.factory.resolveComponentFactory(
this.genericChild
);
const ref = this.childsContainer.createComponent(componentFactory);
ref.instance.geneData = this.geneData;
ref.instance.geneSelection.subscribe(event => {
this.geneSelection.emit(event);
});
this.cdr.detectChanges();
}
}
Replace the template in your main component with something like the following, and create an @Input to pass the dynamic component (genericChild).
<ng-template pTemplate="rowexpansion" let-rowData>
<tr>
<child-wrapper
[genericChild]="genericChild"
[geneData]="rowData"
(geneSelection)="selection($event)"
></child-wrapper>
</tr>
</ng-template>
Then all you need to do is:
//app.component.html
<bio-tables [genericChild]="geneChildComponent"></bio-tables>
//app.component.ts
geneChildComponent: Type<GeneChildComponent> = GeneChildComponent;
Upvotes: 1
Reputation: 12196
you can pass the template and then render it however you want
app.component.html
<bio-tables ... [rowExpansionTpl]="geneTpl">
</bio-tables>
<ng-template #geneTpl let-params="params">
<gene-child [geneName]="params.gene" (geneSelection)="selection(params)"> </gene-child>
</ng-template>
bio-tables.component.html
<div>
<ng-container *ngTemplateOutlet="rowExpansionTpl; context: {params: {gene: 'anything'}}"></ng-container>
</div>
Upvotes: 3