Search code examples
angularprimengng-templateng-container

Child doesn't render template passed by parent


Well, this is my parent component where I am trying to pass the template nodeTemplate to the child ils-tree

<div class="nodes-panel">
    <ils-tree layout="horizontal" [json]="nodes" [template]="nodeTemplate">
    </ils-tree>
</div>

<ng-template #nodeTemplate>
    <ng-template let-node  pTemplate="default">
        <p class="node-type">{{node.data.nodeType}}</p>
        <p class="node-name">{{node.data.name}}</p>
    </ng-template>
    <ng-template let-node  pTemplate="orgNode">
        <p class="org-node-name">{{node.data.name}}</p>
    </ng-template>
</ng-template>

The child component ils-tree's HTML looks this way

<p-tree
  [value]="nodes"
  [layout]="layout"
  selectionMode="single"
  [(selection)]="selectedNode"
  [loading]="loading"
>
  <ng-container *ngTemplateOutlet="template"></ng-container>
</p-tree>

and the controller file has

@Input()
template: TemplateRef<any>;

Basically, the ps are nowhere to be seen and yes, the data json is being passed successfully. Help!

P.S The template when embedded directly, in between, works. That is,

<p-tree
  [value]="nodes"
  [layout]="layout"
  selectionMode="single"
  [(selection)]="selectedNode"
  [loading]="loading"
>
  <ng-template let-node  pTemplate="default">
        <p class="node-type">{{node.data.nodeType}}</p>
        <p class="node-name">{{node.data.name}}</p>
    </ng-template>
    <ng-template let-node  pTemplate="orgNode">
        <p class="org-node-name">{{node.data.name}}</p>
    </ng-template>
</p-tree>

Solution

  • I think primeng tree doesn't let you use a template inside another templates with the pTemplate correct.

    I could make a workaround declaring the templates separated and passing the type too. The main page would look like:

    <ils-tree [templates]="[{type:'orgNode',template:templateOrg},
    {type:'default',template:templateDefault}]"
     [data]="data"></ils-tree>
    
    <ng-template let-node="node" pTemplate="default" #templateDefault>
        <p class="node-type">{{node.label}}</p>
    </ng-template>
    
    <ng-template let-node="node" pTemplate="orgNode" #templateOrg>
        <p class="org-node-name">{{node.label}}</p>
    </ng-template>
    

    Then the ils-tree.html would look like:

    <p-tree [value]="data">
        <ng-container *ngFor="let temp of templates">
        <ng-template [pTemplate]="temp.type" let-node>
            <ng-template [ngTemplateOutlet]="temp.template" [ngTemplateOutletContext]="{
                     node:node
                   }">
                </ng-template>
            </ng-template>
        </ng-container>
    </p-tree>
    

    The trick here is passing the node you are using as a context with ngTemplateOutletContext to your template so you can use it in the main with the let-node="node".

    The ils-tree.ts would look like:

      @Input() templates: any[];
      @Input() data: any;
    

    In my example I added a model for the templates to make it more easy to read.

    You have the live example here:
    https://stackblitz.com/edit/angular-tree-templates