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

2

8

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

Gigolo answered 9/11, 2018 at 5:57 Comment(1)
Hi - You source doesn't seems to be the working version - check you please check itIndefeasible
P
5

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.

Personally answered 9/11, 2018 at 6:54 Comment(2)
This is was exactly I was trying aside before posting an answer, nice way :) +1Nimmons
But I have to admit that, I was trying to load template first and then lazily going to instantiate p-table imperatively from Component.Nimmons
I
0

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>
Icj answered 9/11, 2018 at 6:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.