首页 > 解决方案 > 结构指令上下文可以包含函数吗?

问题描述

我创建了一个简单的结构指令来帮助为一些自定义组件生成唯一 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)但没有用。我想把这一切都包含在这个指令/上下文中。

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

标签: angulartypescriptangular-directive

解决方案


所以看起来这里的主要限制是使用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>

推荐阅读