tris
tris

Reputation: 1049

Get ViewChildren Template By Id

In my component I get a list of its markup templates by using ViewChildren:

@ViewChildren(TemplateRef) private _templates: QueryList<TemplateRef<unknown>>;

In Angular8 I was not able to filter them by an Id, so i needed to look for an internal property - which was somehow a bit hacky:

let template = this._templates.find(t => (<any>t)._def.references[id]) : null;

Now, with Angular 9, this doesn't work anymore. I checked the object and found a new "hack":

this._templates.find(t => (<any>t)._declarationTContainer?.localNames?.includes(id)) : null;

But is there any new or clean solution for this scenario?

Still hoping for a solution that works without a custom Directive, eg. MatTab probably does something similar, too:

<mat-tab>
    <ng-template mat-tab-label>
        ...
    </ng-template>

    <ng-template matTabContent>
        ...
    </ng-template>
</mat-tab>

Upvotes: 5

Views: 5551

Answers (1)

yurzui
yurzui

Reputation: 214175

A clean solution for your scenario is to create a NgTemplateNameDirective directive with ng-template[name] selector:

import { Directive, Input, TemplateRef } from '@angular/core';

@Directive({
  selector: 'ng-template[name]'
})
export class NgTemplateNameDirective {
  @Input() name: string;

  constructor(public template: TemplateRef<any>) { }
}

after that create templates like:

<ng-template name="t1"></ng-template>
<ng-template name="t2"></ng-template>

then query NgTemplateNameDirective instead of TemplateRef:

@ViewChildren(NgTemplateNameDirective) private _templates: QueryList<NgTemplateNameDirective>;

and finally search your template by name

getTemplateRefByName(name: string): TemplateRef<any> {
  const dir = this._templates.find(dir => dir.name === name);
  return dir ? dir.template : null
}

Works fine in both view engines: ViewEngine and Ivy.

Ng-run Example

Upvotes: 16

Related Questions