通过ID获取ViewChildren模板

5
在我的组件中,我使用ViewChildren获取其标记模板列表:
@ViewChildren(TemplateRef) private _templates: QueryList<TemplateRef<unknown>>;

在Angular8中,我无法通过ID筛选它们,所以我需要寻找一个内部属性 - 这在某种程度上有点欺骗性:

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

现在,使用 Angular 9,这个方法已经失效了。我查看了对象并找到了一种新的“hack”:

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

但是是否有新的或更干净的解决方案呢?

仍然希望能够找到一种不需要自定义指令的解决方案,例如MatTab可能也会做类似的事情:

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

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

你能否详细说明你的最终目标是什么?模板是什么样子的,你想要一个什么样的参考? - Michael
结尾的 : null 看起来很奇怪,应该会给你一个语法错误。这真的能工作吗? - ShamPooSham
嘿,抱歉,我很忙 - 希望有人知道这个问题,下面的答案非常完美。结尾的 : null 是因为一个分配问题。 - tris
1个回答

12
一个适用于您情况的干净解决方案是创建一个具有 ng-template[name] 选择器的 NgTemplateNameDirective 指令:

一个适用于您情况的干净解决方案是创建一个具有 ng-template[name] 选择器的 NgTemplateNameDirective 指令:

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

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

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

之后创建类似以下的模板:

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

那么查询NgTemplateNameDirective而不是 TemplateRef

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

最后,按名称搜索您的模板

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

在视图引擎(ViewEngine)和Ivy中都能正常工作。

Ng-run示例


太棒了!正是我想要的!但是有没有可能使用常规的 #id?这样会更好。 - tris
@tris 如果你想使用常规的 #id,那么就用你的hacky解决方案,否则创建指令。Angular Material也是通过模板来实现相同的技巧。 - yurzui
啊,好的 - 我看错了,他们确实使用指令而不是ID。问题解决了,谢谢 :) - tris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接