6

Is it possible to write reusable ng-template? A lot of my components use exactly the same ng-template.
For example:

<kendo-grid>
 <kendo-grid-column field="group">
 <ng-template kendoGridEditTemplate let-dataItem="dataItem" let-formGroup="form">
 <kendo-dropdownlist #listGroups [data]="groups"
 textField="title"
 valueField="id"
 [valuePrimitive]="true"
 [filterable]="true"
 [formControl]="form.get('groupId')">
 </kendo-dropdownlist>
 </ng-template>
 </kendo-grid-column>
</kendo-grid>

I do not want to repeat this template and logic behind in all my components. I could write custom component and shrink this code to:

<kendo-grid>
 <kendo-grid-column field="group">
 <ng-template kendoGridEditTemplate let-dataItem="dataItem" let-formGroup="form">
 <my-custom-component [formControl]="form.get('groupId')">
 </my-custom-component>
 </ng-template>
 </kendo-grid-column>
</kendo-grid>

but I want to do more:

<kendo-grid>
 <kendo-grid-column field="group">
 <ng-template [ngTemplateOutlet]="templateFromAnotherSource">
 </ng-template>
 </kendo-grid-column>
</kendo-grid>

I found this thread and this which describes ngTemplateOutlet, but not how to share templates between multiple components.

asked Sep 6, 2017 at 10:14

2 Answers 2

7

The problem is that ng-template has to be compiled. To understand why read Here is what you need to know about dynamic components in Angular.

Now, a template can only be compiled as part of a component right now. So you need to define a component with this template and then you can get access to this template factory either using viewChild or a directive. With viewChild you depend on life-cycle hooks and change detection so I'd go with directive approach. Here is the pseudocode:

@Component() {
 template: '<ng-template requestor>...</ng-template>'
}
class NgTemplateProviderComponent {
 t: TemplateRef;
 register(t) {
 this.t = t;
 }
}
@Directive() {
 selector: 'requestor; 
}
class TemplateRequestor {
 constructor(t: TemplateRef, p: NgTemplateProviderComponent) {
 p.register(t);
 }
}

To learn more about this approach of using a directive to get templateRef read Here is how to get ViewContainerRef before @ViewChild query is evaluated.

Then, you need to get access to the NgTemplateProviderComponent component factory, create its instance to get the templateRef:

class SomeComponent {
 constructor(r: ComponentFactoryResolver, i: Injector) {
 const f = r.resolveComponentFactory(NgTemplateProviderComponent);
 const templateRef =f.create(i).instance.t;
 }
}

and only then you can use ngTemplateOutlet directive to render the template.

answered Sep 6, 2017 at 11:13
Sign up to request clarification or add additional context in comments.

2 Comments

Hi. After reading a few of your posts in blog, I decided to go with my second option (custom control in template). For one line of extra code, this seems to much. I was looking more for design solution to insert template. No need to compile, since this would be done automatically. Anyway, great post. Thank you. Does this solution works with AOT?
it should work with AOT. No need to compile, since this would be done automatically - if you use webpack, I guess you write a plugin to parse the template and insert the partial template, but that again will probably be not what you wanted
4

A different approach to solve this problem is to use ng-container to display your content. As Max Koretskyi posted, you can follow a class directive approach in order to make your component reusable in any module. However, if you want just a simple way to make your HTML looks a little bit ugly when same code is needed (also DRY principle) you can do this:

<ng-template #YOUR-NG-TEMPLATE-NAME let-YOUR-PARAMETER="YOUR-PARAMETER">
 // Your large implementation
</ng-template>
...
<kendo-grid-column field="whatever">
 <ng-template kendoGridEditTemplate let-YOUR-PARAMETER="YOUR-VARIABLE">
 <ng-container [ngTemplateOutlet]="YOUR-NG-TEMPLATE-NAME"
 [ngTemplateOutletContext]="{ YOUR-PARAMETER: YOUR-PARAMETER }">
 </ng-container>
 </ng-template>
</kendo-grid-column>

This can be useful when a large amount of code is needed to be reusable, if you just want to display attributes, just use ng-template with some Kendo directive as usual.

Hopefully this helps you.

answered Jul 27, 2021 at 1:17

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.