Search code examples
angularng-template

How to declare an instance of TemplateRef in the component code to reuse it multiple times in the markup?


I have several controls where I pass a template. It's the same one for each such occurrence and it appears as a good idea to avoid the code redundancy.

<app-lookup [data]="lookupData[0]">
  <ng-template let-ctx>{{ctx.name}} ...</ng-template>
</app-lookup>
...
<app-lookup [data]="lookupData[99]">
  <ng-template let-ctx>{{ctx.name}} ...</ng-template>
</app-lookup>

I've found a discussion seemingly related to my desire but checking out the linked fiddle doesn't contain any HTML for the component, which makes me suspect that it's less related than originally expected.

I'd like to do something like this in the markup:

<app-lookup *ngFor="index of [1, ..., 99]" [data]="lookupData[index]">
  <ng-container [ngTempalteOutput]="template"></ng-container>
</app-lookup>

...and provide the template from the component code:

@ContentChild(TemplateRef) template: TemplateRef<unknown> = ???;

...but I haven't figured out a way to provide anything useful for ???.


Solution

  • you should not put anything in place of ???. @ContentChild decorator will make sure angular populates the field in the class with a corresponding content child.

    In some project you can meet helper directives for explicit and clean template marking. In your case it would look like this:

    @Directive({selector: '[lookupContent]'})
    class LookupContentDirective{
      constructor(public template: TemplateRef) {}
    }
    
    ....
    class AppLookupComponent {
      @ContentChild(LookupContentDirective) content?: LookupContentDirective;
    ...
    // app-lookup.component.html
    <div *ngTemplateOutlet="content?.template; context: context"></div>
    ...
    // usage
    <app-lookup>
     <li *lookupContent>li will be a template</li>
    </app-lookup>