3

I'm using PrimeNG 12.0.1 and its Table to display data in my Angular application.

I have separate @Component which contains <p-table> in html template. Inside <p-table> there's ng-templates to display table parts like pTemplate="colgroup", pTemplate="header", pTemplate="body" etc.

I would like to move these parts to separate files to be able to reuse them in new Component which will also have <p-table>. How to achieve that to move these elements to other file (Component?) and have working table?

Below some current code fragments:

<p-table #table [value]="userDataSource.data$ | async" [columns]="displayedColumns" ........>

  <ng-template pTemplate="colgroup" let-columns>
    <colgroup>
      <col *ngFor="let col of columns" [ngStyle]=".........">
    </colgroup>
  </ng-template>

  <ng-template pTemplate="header" let-columns>
    <tr>
      <ng-container *ngFor="let col of columns">
          .........
      </ng-container>
    </tr>
  </ng-template>

  <ng-template pTemplate="body" let-row let-columns="columns" let-expanded="expanded">
    <tr (click)="rowClicked(row)" class="...........">
      <ng-container *ngFor="let column of columns">
           ................
      </ng-container>
    </tr>
  </ng-template>

</p-table>
user3626048
  • 706
  • 4
  • 19
  • 52

2 Answers2

3

I have used ngTemplateOutlet for this purpose. It needs some additional tinkering though, as Angular screams about No provider for Table when trying to use it without adding as provider. So I ended up doing... for the the table component, which I have called TableWrapperComponent... need to import Table and TableService from Primeng and to use them as provider:

import { Table, TableService } from 'primeng/table';

export function tableFactory(tableComponent: TableWrapperComponent) {
  return tableComponent.primengTable;
}

@Component({
  selector: 'app-table-wrapper',
  templateUrl: './table-wrapper.component.html',
  styleUrls: ['./table-wrapper.component.scss'],
  providers: [
    TableService,
    {
      provide: Table,
      useFactory: tableFactory,
      deps: [TableWrapperComponent]
    }
  ]
})

//....

All good, so next the contentchildren for the template. I only have header and body here, but you can add all the parts you use :)

 @ContentChild('header') headerTemplate: TemplateRef<any>;
 @ContentChild('body') bodyTemplate: TemplateRef<any>;
 @ViewChild('primengTable', { static: true }) public primengTable: Table;

Cool, now we have the "parts" done, now use them in TableWrapperComponent:

<p-table>
  <ng-template pTemplate="header">
    <tr>
      <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
    </tr>
  </ng-template>
  <ng-template pTemplate="body" let-item>
    <tr>
      <ng-container *ngTemplateOutlet="bodyTemplate;context:{$implicit:item}"></ng-container>
    </tr>
  </ng-template>
</p-table>

All good, now we can use those for example the body part in another component:

<app-table-wrapper>
  <ng-template let-item #body>
    <td>.....All magic....</td>
  </ng-template>
</app-table-wrapper>
AT82
  • 71,416
  • 24
  • 140
  • 167
  • 1
    thank you for great answer, I will try it today! – user3626048 Nov 26 '21 at 10:06
  • I tried your method but I must be doing something wrong because table header and body is not showing when I'm using template outlet. I made some example https://stackblitz.com/edit/angular-ivy-5yhtd1 Could you please check it? – user3626048 Dec 03 '21 at 11:48
0

A belated comment on the good example on this page, but maybe it will be useful to someone. Don't forget to add the #primengTable ID on the table. And the rest works for me.

<p-table #primengTable>
  <ng-template pTemplate="header">
    <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
  </ng-template>
  ...
</p-table>