Componente dinámico dentro de ngx-datatable row-detail

9

Estoy creando una tabla de datos reutilizable usando ngx-datatable y me gustaría tener componentes dinámicos representados dentro de los detalles de la fila. El componente de tabla de datos recibe una clase de componente como argumento de un módulo principal y yo uso ComponentFactory para crear un Componente. Puedo ver que el constructor y los métodos onInit se están ejecutando para el componente dinámico, pero no se está adjuntando al DOM.

Así es como se ve el html de la tabla de datos para el detalle de fila:

 <!-- [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] -->

Y así es como se ve mi archivo .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);
}

Otro punto es que si mi #dynamicPlaceholderplantilla ng se coloca fuera de ngx-datatable, funciona y el módulo dinámico se representa y se muestra.

Raghav Kanwal
fuente
1
Esto tiene que ver con la proyección de contenido. Cualquier cosa colocada entre una etiqueta de componente no se representa a menos que el componente tenga una <ng-content>etiqueta para representar cualquier marcado anidado.
C_Ogoo
¿Podría por favor ayudarme con un ejemplo rápido para ayudar en mi caso?
Raghav Kanwal

Respuestas:

2

No podemos representar un componente en una Plantilla ( <ng-template>) en tiempo de ejecución createComponent
porque Angular procesa las plantillas afaik en tiempo de compilación. Por lo tanto, necesitamos una solución que funcione en tiempo de compilación.


Solución con inconvenientes

ng-content puede ayudarnos aquí:

<!-- [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] -->

Luego podemos pasar lo que queramos a la vista detallada:

<my-table>From the ouside but I cant access the current row :(</my-table>

Pero hay un problema: no podemos usar ng-contentcuando queremos acceder a la fila actual en la plantilla aprobada.


Solución

Pero ngx-datatablenos cubrió. Podemos pasar una plantilla a la ngx-datatable-row-detaildirectiva:

<ngx-datatable-row-detail [template]="myDetailTemplate "rowHeight="100" (toggle)="onDetailToggle($event)">
</ngx-datatable-row-detail>

La plantilla se puede pasar desde cualquier componente en el exterior a través de una @Inputvariable:

<ng-template #myDetailTemplate let-row="row">
  From the outside with access to the current row: {{row.name}}
</ng-template>

Eche un vistazo a stackblitz , donde escribí un my-tablecomponente como poc.

ChrisY
fuente
0

Definir un componente que expone su contenido como 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>

Use ViewChildpara hacer una propiedad accesible paraTemplateRef

export class DynamicComponent implements OnInit {

  @ViewChild("myTemplate",{static:true}) myTempalte : TemplateRef<any>
...
}

Defina los detalles de su fila sin plantilla

<ngx-datatable-row-detail rowHeight="100" (toggle)="onDetailToggle($event)">
</ngx-datatable-row-detail>

Definir una propiedad para acceder a la directiva.

@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

Editar: jugué con la ngx-datatablefuente, la parte triste de él ngx-datatable-row-detailno es un componente sino una directiva y no está asociada al DOM. Entonces no tiene ViewContainerref. Esto hace que inyectarle elementos sea un poco difícil. Lo que puede hacer es definir plantillas en su componente y usar TemplateRefsy asignarlas donde representa su componente.

Eldar
fuente
Gracias por la entrada, traté de adoptar su método, pero recibo un el.setAttribute is not a functionerror en el método componentFactory.create. ¿Alguna idea de por qué eso puede estar sucediendo? this.dynamicPlaceholder.elementRef.nativeElement devuelve un comentario, ¿podría ser eso?
Raghav Kanwal
@RaghavKanwal ve mi respuesta actualizada.
Eldar