Angular `ng-content` is not working as expected with primeNg tables

4k views Asked by At

I want to create a reusable table component which uses primeNg to render ui. I created a table.component.html and .ts for that. Now i want to render content for the table which will be table headers (th) and table body (body).

To do that, i am writing th and tbody implementation as a content of table and trying to render it in table.component.html using <ng-content></ng-content>. But the table is not displaying.

I tried adding the th and tbody directly in table.component.html and it displays the table. shouldn't ng-content do the same thing because the content has the same html?

Here is the link to snippet with example. Check table.component.html under shared dir. And app.component.html for initial start. comment the ng-content line and uncomment remaining lines in table.component.html and you should see the table. https://stackblitz.com/edit/angular-playground-kwudxn?file=app%2Fshared%2Ftable%2Ftable.component.html

2

There are 2 answers

2
Ludevik On BEST ANSWER

Problem with your application is that ng-template doesn't render anything so ng-content doesn't render anything either. I don't see currently any added value in your TableComponent as it currently only resends the templates, but that's maybe because it is just a demo and it will have some added value in your case.

You need to change your TableComponent to pick up the PrimeTemplates from the content and resend them to p-table:

export class TableComponent implements AfterContentInit {

    @Input()
    public data: any[];
    @ContentChildren(PrimeTemplate)
    templates: QueryList<any>;
    headerTemplate: TemplateRef<any>;
    bodyTemplate: TemplateRef<any>;

    constructor() { }

    gePrimeTemplateByType(type: string): PrimeTemplate {
        return this.templates.find(template => {
            return template.getType() === type;
        });
    }

    ngAfterContentInit() {
        this.headerTemplate = this.gePrimeTemplateByType('header').template;
        this.bodyTemplate = this.gePrimeTemplateByType('body').template;
    }
}

And in your template:

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

Here is complete forked stackblitz demo.

Of course there are other ways to implement this, e.g. your TableComponent could have just 2 @Inputs and just resend them to p-table instead of using PrimeTemplates.

0
Manzer A On

ng-content is basically used for content projection. Try using <ng-template> instead of <ng-content>

Link:- https://angular-2-training-book.rangle.io/handout/components/projection.html

app/child/child.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'child',
  template: `
    <div style="border: 1px solid blue; padding: 1rem;">
      <h4>Child Component</h4>
      <ng-content></ng-content>
    </div>
  `
})
export class ChildComponent {
}

app/app.component.html

 <child>
    <p>My <i>projected</i> content.</p>
  </child>