Dynamic Angular Components via Transclusion

Chris House
3 min readOct 2, 2019

Transclusion is the inclusion of part or all of a component into one or more other components via a template reference. Transclusion is usually performed when the referencing component is displayed, and is normally automatic and transparent to the end user. The result of transclusion is a single integrated component made of parts assembled dynamically from separate sources, possibly stored on different Angular Applications or Angular Libraries.

src: https://twiki.org/cgi-bin/view/Blog/BlogEntry201205x4

The example this article will use is injecting dynamic components into a grid cell.

Scenario: Lets say you are a library developer that maintains a reusable grid component, and you want to expose a column(s) to other developers so they can stick what ever (component) they want inside the template reference. Maybe under certain conditions, they want to customize the display text, put an action button in the cell if the cell data meets a certain condition, or maybe a hyperlink to a different part of the application.

The best case scenario is: You consume the grid and you provide a <ng-template> for your column that you want, and stick what ever you want in the cell.

For the grid, I am using angular material’s grid. The input Table Options contains the column definitions along with a reference to the `templateRef`

<app-material-table [tableOptions]="tableOptions">
</app-material-table>

Here is an example of custom columns and the template:

<ng-template #templateTest let-element="element" let-column="column">
<div class="custom-style-red" *ngIf="column.title == 'Weight'"> {{element}}
</div>
</ng-template>

We will need a reference to the template via ViewChild.

@ViewChild('templateTest') templateTest: TemplateRef<any>;

This is the template that will be inserted into the table. In this case if the column’s title is Weight, we are setting the color of the text to red.

In the implementation of your reusable grid/component, here is how you set up your templateOutlet:

<ng-container *ngIf="column.cellTemplate">
<th mat-header-cell *matHeaderCellDef> {{column.title}} </th>
<td mat-cell *matCellDef="let element">
<ng-template [ngTemplateOutletContext]="{element: element[column.id],column: column}" [ngTemplateOutlet]="column.cellTemplate">
</ng-template>
</td>
</ng-container>

The first line says that if the table configuration for the column has a value for the TemplateRef, then use this code block to display the template via ngTemplateOutlet

ngTemplateOutletContext allows us to pass data from the grid back into our component where we want to customize the cell data. Element is the value of the cell in this example.

When we put this together you have implemented transclusion in Angular!

I took it a step further, and if the column match “Symbol” I put a hyperlink to an info page, and also fire a custom event to show how that works.

For the full StackBlitz working demo and code, click here!

--

--