结构指令上下文可以包含函数吗?

Can a structural directive context contain a function?

我创建了一个简单的结构指令来帮助为一些自定义组件生成唯一的 ID。

import { Directive, DoCheck, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import { v4 as uuid } from 'uuid';

export class UniqueIdContext {
  constructor(private $implicit: string) {}

  at(index: number) {
    return `${this.$implicit}_${index}`;
  }
}

@Directive({
  selector: '[uniqueId]'
})
export class UniqueIdDirective implements DoCheck {
  @Input()
  set uniqueIdFor(uniqueIdFor: string) {
    this._uniqueIdFor = uniqueIdFor;
    this._uniqueIdDirty = true;
  }

  private _uniqueIdFor: string;
  private _uniqueIdDirty = false;

  constructor(
    private templateRef: TemplateRef<UniqueIdContext>,
    private viewContainerRef: ViewContainerRef
  ) {}

  ngDoCheck(): void {
    if (this._uniqueIdDirty) {
      this._uniqueIdDirty = false;
      const prefix = uuid();
      const name = this._uniqueIdFor;
      const id = `${prefix}_${name}`.replace(/-/g, '');
      this.viewContainerRef.createEmbeddedView(
        this.templateRef,
        new UniqueIdContext(id)
      );
    }
  }
}

用法如下:

<div *uniqueId="let id for 'control'">
  <input [attr.id]="id" [formControl]="control">
  <label [attr.for]="id">My Label</label>
</div>

如果我想按原样使用 id,这很有效。但是,我打算在 ngFor 循环中使用它来在每次迭代时为控件生成 id,它会将索引作为生成的 id 的后缀。这就是 UniqueIdContext.at() 函数的目的,但它似乎不起作用。

<ul *uniqueId="let id for 'control'">
  <li *ngFor="let control of controls; index as i">
    <input [attr.id]="at(i)" [formControl]="control">
    <label [attr.for]="at(i)">My Label {{i}}</label>
  </li>
</ul>

我也尝试了 id.at(i)id(i) 但没有用。我想将所有内容都包含在 directive/context.

我需要以某种方式声明模板变量吗?我怎样才能完成这项工作?

所以看起来这里的主要限制是 this 的使用。我需要将该方法绑定到 this,然后为其声明一个模板变量。

export class UniqueIdContext {
  constructor(private $implicit: string) {
    this.at = this.at.bind(this);
  }

  at(index?: number) {
    return index != null ? `${this.$implicit}_${index}` : this.$implicit;
  }
}
<ul *uniqueId="let id for 'control'; at as idAt">
  <li *ngFor="let control of controls; index as i">
    <input [attr.id]="idAt(i)" [formControl]="control">
    <label [attr.for]="idAt(i)">My Label {{i}}</label>
  </li>
</ul>