web-dev-qa-db-fra.com

Composant dynamique à l'intérieur du détail de ligne datable ngx

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é.

9
Raghav Kanwal

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.

2
ChrisY

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 pour TemplateRef

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);
}

Stackblitz

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 TemplateRefs et de les affecter à l'endroit où vous effectuez le rendu de votre composant.

0
Eldar