Componente dinâmico dentro dos detalhes da linha da tabela de dados ngx

9

Estou criando uma tabela de dados reutilizável usando ngx-datatable e gostaria de ter componentes dinâmicos renderizados dentro dos detalhes da linha. O componente de tabela de dados recebe uma classe de componente como argumento de um módulo pai e eu uso ComponentFactory para createComponent. Percebo que o construtor e os métodos onInit estão em execução para o componente dinâmico, mas ele não está sendo anexado ao DOM.

É assim que o html da tabela de dados se parece com os detalhes da linha:

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

E é assim que meu arquivo .ts se parece:

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

Outro ponto é que, se meu #dynamicPlaceholderng-template for colocado fora da ngx-datatable, ele funcionará e o módulo dinâmico será renderizado e exibido.

Raghav Kanwal
fonte
11
Isso tem a ver com projeção de conteúdo. Qualquer coisa colocada entre uma marca de componente não é renderizada, a menos que o componente tenha uma <ng-content>marca para renderizar qualquer marcação aninhada.
C_Ogoo 01/01
Poderia me ajudar com um exemplo rápido para ajudar no meu caso?
Raghav Kanwal

Respostas:

2

Não podemos renderizar um componente em um Template ( <ng-template>) em tempo de execução createComponent
porque os modelos afaik são processados ​​pelo Angular em tempo de compilação. Portanto, precisamos de uma solução que funcione em tempo de compilação.


Solução com desvantagens

ng-content pode nos ajudar aqui:

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

Podemos então passar o que queremos para a visualização de detalhes:

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

Mas há um problema: não podemos usar ng-contentquando queremos acessar a linha atual no modelo passado.


Solução

Mas ngx-datatablenos cobrimos. Podemos passar um modelo para a ngx-datatable-row-detaildiretiva:

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

O modelo pode ser passado a partir de qualquer componente externo através de uma @Inputvariável:

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

Dê uma olhada no stackblitz , onde escrevi um my-tablecomponente como poc.

ChrisY
fonte
0

Defina um componente que expõe seu conteúdo 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 criar uma propriedade acessível paraTemplateRef

export class DynamicComponent implements OnInit {

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

Defina os detalhes da sua linha sem modelo

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

Defina uma propriedade para acessar a diretiva

@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: Eu brinquei com ngx-datatablefonte triste parte dele ngx-datatable-row-detailnão é um componente, mas diretiva e não está ligado ao DOM. Portanto, não tem ViewContainerref. Isso dificulta um pouco a injeção de elementos nele. O que você pode fazer é definir modelos em seu componente e usar TemplateRefs e atribuí-los onde você renderiza seu componente.

Eldar
fonte
Obrigado pela entrada, tentei adotar o seu método, mas estou recebendo el.setAttribute is not a functionerro no método componentFactory.create. Alguma idéia de por que isso pode estar acontecendo? this.dynamicPlaceholder.elementRef.nativeElement retorna um comentário, poderia ser isso?
Raghav Kanwal
@RaghavKanwal veja minha resposta atualizada.
Eldar