網站搜尋

javascript - Angular:如何將一個索引變數從自定義指令共享到另一個指令?


我正在嘗試在兩個 自訂指令之間共享一個索引變數:ngLoop 和 ngDN。

這是 ngLoop 的程式碼:

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

@Directive({
  selector: '[ngLoop]'
})
export class NgLoopDirective {

  @Input() set ngLoop(iter_count: number) {
    this.container.clear();
    for (let i=0; i<iter_count; i++) {
      this.container.createEmbeddedView(this.template);
    }
  }

  constructor(private template: TemplateRef<any>,
              private container: ViewContainerRef) {}

}

這是 ngDN 的代碼:

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

@Directive({
  selector: '[ngDN]'
})
export class NgDNDirective {

  @Input() set ngDN(dn: number) {
    this.renderer.setAttribute(this.elRef, 'data-num', dn.toString());
  }

  constructor(private elRef: ElementRef, private renderer: Renderer2) {}

}

問題:

現在,無論何時我嘗試看看下面 HTML 代碼的效果如何

<div *ngLoop="products.categories.length; let i = index">
                <a href="#"
                   [ngDN]="i"></a>
            </div>

我收到一個錯誤訊息說:

錯誤 TypeError:無法讀取未定義的屬性 'toString' 於 NgDNDirective.set [作為 ngDN] (ng-dn.directive.ts:9) 於 updateProp (core.es5.js:11102) 於 checkAndUpdateDirectiveInline (core.es5.js:10794) 於 checkAndUpdateNodeInline (core.es5.js:12332) 於 checkAndUpdateNode (core.es5.js:12271) 於 debugCheckAndUpdateNode (core.es5.js:13132) 於 debugCheckDirectivesFn (core.es5.js:13073) 於 Object.eval [作為 updateDirectives] (HomeComponent.html:38) 於 Object.debugUpdateDirectives [作為 updateDirectives] (core.es5.js:13058) 於 checkAndUpdateView (core.es5.js:12238)

由此我明白,索引變量 i 並未正確共享。

共享索引變數的正確方式是什麼?

答案#1

你想要達到的語法的去糖形式如下。

<!-- sugared -->
<div *ngLoop="10; let i = index">
  <a href="#" [ngDN]="i"></a>
</div>

<!-- desugared -->
<ng-template [ngLoop]="10" let-i="index">
  <div>
    <a href="#" [ngDN]="i"></a>
  </div>
</ng-template>

《code>let-i="index" 被稱為 上下文。你可以透過將一個物件作為 createEmbeddedView 的第二個參數來設定上下文。

也就是,在 for 迴圈中,你執行以下操作。

for (let i = 0; i < iter_count; i++) {
  this.container.createEmbeddedView(this.template, {
    index: i,
  });
}

這意味著變數 index 將可在 ng-template 中使用。通過說 let-i="index",你將該模板的 index 值分配給一個本地變數 i,該變數僅在模板中的 ng-template 內可用。

這裡有一個 示範。打開控制台,你就會看到數字。

不過你會遇到渲染器的問題,因為當輸入的 setter 被呼叫時,該元素尚未可用於樣式設定。你需要將它延後到 AfterViewInit。但是你可以先 console.log 並註解掉你的渲染器方法,以確認上面的確是有效的。