Angular ContentChildren 获取指令输入和 TemplateRef

Angular ContentChildren get directive Inputs and TemplateRef

我正在尝试为 ng-templateinput 参数获取 TemplateRef
app.component.html:

<my-parent>
    <ng-template my-directive title="Title1" let-dataItem="dataItem">
        <div>{{dataItem|json}}</div>
    </ng-template>
</my-parent>

问题是我只能得到TemplateRef(标题未定义):
my-parent.html:

<div *ngFor="let detail of details" [title]="detail.title"> //!!! detail.title is undefined
  <ng-container *ngTemplateOutlet="detail;context:{dataItem: dataItem}"></ng-container>
</div>

my-parent.ts

@ContentChildren(MyDirective, { read: TemplateRef }) details: QueryList<MyDirective>;

或者我可以获取输入参数:
my-parent.ts

@ContentChildren(MyDirective) details: QueryList<MyDirective>;   

//in html detail.title is defined, but detail is not template and I get exception in line 
<ng-container *ngTemplateOutlet="detail;context:{dataItem: dataItem}"></ng-container>

异常:

TypeError: templateRef.createEmbeddedView is not a function

我想我需要这个版本的 ContentChildren:

@ContentChildren(MyDirective, { read: TemplateRef }) details: QueryList<MyDirective>;

但是我怎样才能得到 MyDirective 输入参数(在这种情况下是 title)?

我知道我可以同时使用:

@ContentChildren(MyDirective, { read: TemplateRef }) detailsRefs: QueryList<MyDirective>;
@ContentChildren(MyDirective) detailsInputs: QueryList<MyDirective>;

然后合并到新数组中:

public ngAfterViewInit(): void
{
  const refs = this.detailsRefs.toArray();
  const inputs = this.detailsInputs.toArray();
  for (let i = 0; i < inputs.length; i++)
    this.details.push({templateRef: refs[i], inputs: inputs[i]});
}

但肯定有更好的方法。

您可以通过 my-directive 中的输入读取 title,然后从那里读取它,为此您需要删除 {read: TemplateRef}:

@ContentChildren(MyDirective) details: QueryList<MyDirective>;
...
detail.title

据我所知,对于结构指令,输入需要以选择器为前缀。

@Directive({ selector: 'myDirective', ...})
class MyDirective {
  @Input() myDirectiveTitle:string;
}

并像

一样使用它
 <ng-template myDirective title="Title1" let-dataItem="dataItem">

并使用

阅读标题
detail.myDirectiveTitle

另见 https://angular.io/guide/structural-directives

这个代码

@ContentChildren(MyDirective, { read: TemplateRef }) details: QueryList<MyDirective>;

应该会导致错误,因为当您读取 TemplateRef 时,detail 应该是 QueryList<TemplateRef>.

类型

可以用DI来完成:

@Directive({
  selector: '[my-directive]'
})
export class MyDirective  {
  @Input() title: string;

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

现在应该很容易理解我们可以利用前面的指令,例如:

parent.component.ts

@ContentChildren(MyDirective) details: QueryList<MyDirective>;

parent.component.html

<ng-container *ngTemplateOutlet="detail.templateRef
                                       ^^^^^^^^^^^^^

Stackblitz Example