Je crée une table de données réutilisable à l'aide de ngx-datatable et je voudrais que les composants dynamiques soient rendus à l'intérieur du détail de la ligne. Le composant datatable reçoit une classe de composants comme argument d'un module parent et j'utilise ComponentFactory pour créerComponent. Je peux voir que le constructeur et les méthodes onInit sont en cours d'exécution pour le composant dynamique mais qu'il n'est pas attaché au DOM.
Voici à quoi ressemble le HTML datatable pour le détail de la ligne:
<!-- [Row Detail Template] -->
<ngx-datatable-row-detail rowHeight="100" #myDetailRow (toggle)="onDetailToggle($event)">
<ng-template let-row="row" #dynamicPlaceholder let-expanded="expanded" ngx-datatable-row-detail-template>
</ng-template>
</ngx-datatable-row-detail>
<!-- [/Row Detail Template] -->
Et voici à quoi ressemble mon fichier .ts:
@ViewChild('myDetailRow', {static: true, read: ViewContainerRef}) myDetailRow: ViewContainerRef;
@ViewChild('dynamicPlaceholder', {static: true, read: ViewContainerRef}) dynamicPlaceholder: ViewContainerRef;
renderDynamicComponent(component) {
var componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
var hostViewConRef1 = this.myDetailRow;
var hostViewConRef2 = this.dynamicPlaceholder;
hostViewConRef1.createComponent(componentFactory);
hostViewConRef2.createComponent(componentFactory);
}
Un autre point est que si mon #dynamicPlaceholder
ng-template est placé en dehors de ngx-datatable, il fonctionne et le module dynamique est rendu et affiché.
Nous ne pouvons pas rendre un composant dans un modèle (<ng-template>
) lors de l'exécution avec createComponent
car les modèles afaik sont traités par Angular au moment de la compilation. Nous avons donc besoin d'une solution qui fonctionne au moment de la compilation.
Solution avec des inconvénients
ng-content
peut nous aider ici:
<!-- [Row Detail Template] -->
<ngx-datatable-row-detail rowHeight="100" (toggle)="onDetailToggle($event)">
<ng-template let-row="row" let-expanded="expanded" ngx-datatable-row-detail-template>
<ng-content></ng-content>
</ng-template>
</ngx-datatable-row-detail>
<!-- [/Row Detail Template] -->
Nous pouvons ensuite passer tout ce que nous voulons à la vue de détail:
<my-table>From the ouside but I cant access the current row :(</my-table>
Mais il y a un problème: Nous ne pouvons pas utiliser ng-content
lorsque nous voulons accéder à la ligne actuelle dans le modèle passé.
Solution
Mais ngx-datatable
nous a couverts. Nous pouvons transmettre un modèle à langx-datatable-row-detail
directive:
<ngx-datatable-row-detail [template]="myDetailTemplate "rowHeight="100" (toggle)="onDetailToggle($event)">
</ngx-datatable-row-detail>
Le modèle peut ensuite être transmis depuis n'importe quel composant à l'extérieur via un @Input
variable:
<ng-template #myDetailTemplate let-row="row">
From the outside with access to the current row: {{row.name}}
</ng-template>
Jetez un oeil au stackblitz , où j'ai écrit un my-table
composant comme poc.
Définissez un composant qui expose son contenu comme
TemplateRef
<ng-template #myTemplate let-row="row" let-expanded="expanded" ngx-datatable-row-detail-template>
<div><strong>Address</strong></div>
<div>{{ row?.address?.city }}, {{ row?.address?.state }}</div>
</ng-template>
Utilisez
ViewChild
pour créer une propriété accessible pourTemplateRef
export class DynamicComponent implements OnInit {
@ViewChild("myTemplate",{static:true}) myTempalte : TemplateRef<any>
...
}
Définissez les détails de votre ligne sans modèle
<ngx-datatable-row-detail rowHeight="100" (toggle)="onDetailToggle($event)">
</ngx-datatable-row-detail>
Définir une propriété pour accéder à la directive
@ViewChild(DatatableRowDetailDirective,{static:true}) templ:DatatableRowDetailDirective;
constructor(
private cfr: ComponentFactoryResolver, //import cfr
)
....
toggleExpandRow(row) {
const factory = this.cfr.resolveComponentFactory<DynamicComponent>(
DynamicComponent
);
const component = factory.create(this.injector,[]); //create component dynamically
this.templ._templateInput = component.instance.myTempalte; // set directives template to your components template
this.table.rowDetail.toggleExpandRow(row);
}
Edit: J'ai joué avec ngx-datatable
source triste partie de celui-ci ngx-datatable-row-detail
n'est pas un composant mais une directive et il n'est pas attaché au DOM. Il n'a donc pas de ViewContainer
ref. Cela rend l'injection d'éléments un peu difficile. Ce que vous pouvez faire est de définir des modèles dans votre composant et d'utiliser TemplateRef
s et de les affecter à l'endroit où vous effectuez le rendu de votre composant.