Angular: 如何将自定义指令中的索引变量共享给另一个指令?
Angular: How to share an index variable from a custom directive to another?
我正在尝试在两个 custom 指令之间共享一个索引变量: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>
我收到一条错误消息:
ERROR TypeError: Cannot read property 'toString' of undefined
at NgDNDirective.set [as ngDN] (ng-dn.directive.ts:9)
at updateProp (core.es5.js:11102)
at checkAndUpdateDirectiveInline (core.es5.js:10794)
at checkAndUpdateNodeInline (core.es5.js:12332)
at checkAndUpdateNode (core.es5.js:12271)
at debugCheckAndUpdateNode (core.es5.js:13132)
at debugCheckDirectivesFn (core.es5.js:13073)
at Object.eval [as updateDirectives] (HomeComponent.html:38)
at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13058)
at checkAndUpdateView (core.es5.js:12238)
从中我了解到索引变量 i
未正确共享。
共享索引变量的正确方法是什么?
您要实现的语法的脱糖形式如下。
<!-- 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>
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
内可用。
一个demo is here。打开控制台,您将看到数字。
不过渲染器会出现问题,因为在调用输入的 setter 时元素尚不可用于样式设置。您需要将其推迟到 AfterViewInit
。但是你现在可以 console.log
并注释掉你的渲染器方法,看看上面的方法是否确实有效。
我正在尝试在两个 custom 指令之间共享一个索引变量: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>
我收到一条错误消息:
ERROR TypeError: Cannot read property 'toString' of undefined at NgDNDirective.set [as ngDN] (ng-dn.directive.ts:9) at updateProp (core.es5.js:11102) at checkAndUpdateDirectiveInline (core.es5.js:10794) at checkAndUpdateNodeInline (core.es5.js:12332) at checkAndUpdateNode (core.es5.js:12271) at debugCheckAndUpdateNode (core.es5.js:13132) at debugCheckDirectivesFn (core.es5.js:13073) at Object.eval [as updateDirectives] (HomeComponent.html:38) at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13058) at checkAndUpdateView (core.es5.js:12238)
从中我了解到索引变量 i
未正确共享。
共享索引变量的正确方法是什么?
您要实现的语法的脱糖形式如下。
<!-- 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>
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
内可用。
一个demo is here。打开控制台,您将看到数字。
不过渲染器会出现问题,因为在调用输入的 setter 时元素尚不可用于样式设置。您需要将其推迟到 AfterViewInit
。但是你现在可以 console.log
并注释掉你的渲染器方法,看看上面的方法是否确实有效。