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

9

Je crée une table de données réutilisable en utilisant 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 composant 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 #dynamicPlaceholdermodèle ng est placé en dehors de ngx-datatable, cela fonctionne et le module dynamique est rendu et affiché.

Raghav Kanwal
la source
1
Cela concerne la projection de contenu. Tout élément placé entre une balise de composant n'est pas rendu, sauf si le composant possède une <ng-content>balise pour restituer tout balisage imbriqué.
C_Ogoo
Pourriez-vous s'il vous plaît m'aider avec un exemple rapide pour aider dans mon cas?
Raghav Kanwal

Réponses:

2

Nous ne pouvons pas rendre un composant dans un Template ( <ng-template>) au moment 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 l'utiliser ng-contentlorsque nous voulons accéder à la ligne actuelle dans le modèle passé.


Solution

Mais ngx-datatablenous a couverts. Nous pouvons passer un modèle à la ngx-datatable-row-detaildirective:

<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 extérieur via une @Inputvariable:

<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-tablecomposant comme poc.

ChrisY
la source
0

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

Stackblitz

Edit: j'ai tripoté la ngx-datatablesource avec une triste partie, ce ngx-datatable-row-detailn'est pas un composant mais une directive et elle n'est pas attachée au DOM. Il n'a donc pas de ViewContainerréf. Cela rend l'injection d'éléments un peu difficile. Ce que vous pouvez faire, c'est définir des modèles dans votre composant et utiliser TemplateRefs et les affecter à l'endroit où vous rendez votre composant.

Eldar
la source
Merci pour l'entrée, j'ai essayé d'adopter votre méthode mais je reçois une el.setAttribute is not a functionerreur sur la méthode componentFactory.create. Une idée de pourquoi cela peut arriver? this.dynamicPlaceholder.elementRef.nativeElement renvoie un commentaire, est-ce possible?
Raghav Kanwal
@RaghavKanwal voir ma réponse mise à jour.
Eldar