angular:调用el.setAttribute导致错误
angular: Calling el.setAttribute results in an error
我正在尝试在每个元素(标记为 el
)中设置一个新属性(定义为 'data-num'),引用 [ngDN](作为指令的实例NgDNDirective
)。
概念:
下面的代码解释了 NgDNDirective
的工作原理:
TS部分:
import { Directive, Input, ElementRef, Renderer2, EventEmitter } from '@angular/core';
@Directive({
selector: '[ngDN]'
})
export class NgDNDirective {
private dn: number = -1
@Input() set ngDN(dn: number) {
this.dn = dn
}
@Input() set EV(ref: {ev: EventEmitter<void>}) {
ref.ev.subscribe(() => {
console.log('data-num:', this.dn)
this.renderer.setAttribute(this.elRef, 'data-num', this.dn.toString())
})
}
constructor(private elRef: ElementRef,
private renderer: Renderer2) {}
}
@Directive({
selector: '[ngLoop]'
})
export class NgLoopDirective {
@Input() set ngLoop(iter_count: number) {
this.container.clear()
for (let i=0; i<iter_count; i++) {
let ee: EventEmitter<void> = new EventEmitter<void>()
let ref = {ev: ev}
let ev = this.container.createEmbeddedView(this.template, {index: i, ev: ref})
ev.detectChanges()
ee.emit()
}
}
constructor(private template: TemplateRef<any>,
private container: ViewContainerRef) {}
}
HTML部分:
<ng-template [ngLoop]="10" let-i="index" let-ref="ev">
<a href="#" [ngDN]="i" [EV]="ref"></a>
</ng-template>
问题:
经过运行测试,控制台显示如下信息:
data-num: 0
ERROR TypeError: el.setAttribute is not a function Stack trace:
../../../platform-browser/@angular/platform-browser.es5.js/DefaultDomRenderer2.prototype.setAttribute@http://localhost:8888/vendor.bundle.js:78803:13
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:66266:9
set/<@http://localhost:8888/main.bundle.js:869:17
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56260:36
../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.__tryOrUnsub@http://localhost:8888/vendor.bundle.js:1558:13
../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1505:17
../../../../rxjs/Subscriber.js/Subscriber.prototype._next@http://localhost:8888/vendor.bundle.js:1445:9
../../../../rxjs/Subscriber.js/Subscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1409:13
../../../../rxjs/Subject.js/Subject.prototype.next@http://localhost:8888/vendor.bundle.js:1153:17
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56234:54
set@http://localhost:8888/main.bundle.js:928:17
updateProp@http://localhost:8888/vendor.bundle.js:63715:5
checkAndUpdateDirectiveInline@http://localhost:8888/vendor.bundle.js:63407:19
checkAndUpdateNodeInline@http://localhost:8888/vendor.bundle.js:64945:17
checkAndUpdateNode@http://localhost:8888/vendor.bundle.js:64884:16
debugCheckAndUpdateNode@http://localhost:8888/vendor.bundle.js:65745:38
debugCheckDirectivesFn@http://localhost:8888/vendor.bundle.js:65686:13
View_HomeComponent_4/<@ng:///AppModule/HomeComponent.ngfactory.js:121:9
debugUpdateDirectives@http://localhost:8888/vendor.bundle.js:65671:12
checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64851:5
callViewAction@http://localhost:8888/vendor.bundle.js:65216:21
execEmbeddedViewsAction@http://localhost:8888/vendor.bundle.js:65174:17
checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64852:5
callViewAction@http://localhost:8888/vendor.bundle.js:65216:21
execComponentViewsAction@http://localhost:8888/vendor.bundle.js:65148:13
checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64857:5
callViewAction@http://localhost:8888/vendor.bundle.js:65216:21
execEmbeddedViewsAction@http://localhost:8888/vendor.bundle.js:65174:17
checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64852:5
callViewAction@http://localhost:8888/vendor.bundle.js:65216:21
execComponentViewsAction@http://localhost:8888/vendor.bundle.js:65148:13
checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64857:5
callWithDebugContext@http://localhost:8888/vendor.bundle.js:66071:39
debugCheckAndUpdateView@http://localhost:8888/vendor.bundle.js:65611:12
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:62782:9
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:57420:58
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:57420:13
next/<@http://localhost:8888/vendor.bundle.js:57297:100
../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2936:17
onInvoke@http://localhost:8888/vendor.bundle.js:56503:24
../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2935:17
../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2686:24
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56434:54
next@http://localhost:8888/vendor.bundle.js:57297:70
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56248:36
../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.__tryOrUnsub@http://localhost:8888/vendor.bundle.js:1558:13
../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1505:17
../../../../rxjs/Subscriber.js/Subscriber.prototype._next@http://localhost:8888/vendor.bundle.js:1445:9
../../../../rxjs/Subscriber.js/Subscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1409:13
../../../../rxjs/Subject.js/Subject.prototype.next@http://localhost:8888/vendor.bundle.js:1153:17
../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56234:54
checkStable@http://localhost:8888/vendor.bundle.js:56468:13
onLeave@http://localhost:8888/vendor.bundle.js:56547:5
onInvokeTask@http://localhost:8888/vendor.bundle.js:56497:17
../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2968:17
../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2736:28
../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:3043:24
invokeTask@http://localhost:8888/polyfills.bundle.js:3915:9
globalZoneAwareCallback@http://localhost:8888/polyfills.bundle.js:3933:17
这意味着从NgLoopDirective
到NgDNDirective
注入的Renderer2实例没有setAttribute
方法。为什么会出现这种情况?
更多信息:
ng -v
_ _ ____ _ _ / \ _ __ __ _ _ _| | __ _ _ __ / | | | | / △ \ | ' \ / _| | | | |/ _
| '| | | | | | | / \| | | | (| | || | |
(| | | | || | | | // __| ||__, |__,||__,||
____|_____||
|/ @angular/cli: 1.2.3 node: 6.11.0 os: linux x64 @angular/animations: 4.3.3 @angular/common: 4.3.3 @angular/compiler:
4.3.3 @angular/core: 4.3.3 @angular/forms: 4.3.3 @angular/http: 4.3.3 @angular/platform-browser: 4.3.3 @angular/platform-browser-dynamic:
4.3.3 @angular/router: 4.3.3 @angular/cli: 1.2.3 @angular/compiler-cli: 4.3.3 @angular/language-service: 4.3.3
您正在使用 'ngDN' 属性作为指令的选择器,
但是您还试图将该属性的值设置为循环索引的值。
使用属性作为选择器应该没问题,但您不应该尝试设置它的值。您的指令有一个名为 'ngDN':
的输入
private dn: number = -1
@Input() set ngDN(dn: number) {
this.dn = dn
}
您可能应该将其更改为:
@Input() dn: number = -1;
然后将模板更改为:
<ng-template [ngLoop]="10" let-i="index" let-ref="ev">
<a href="#" ngDN [dn]="i" [EV]="ref"></a>
</ng-template>
Renderer2#setAttribute(el, name, value)
结束调用 el.setAttribute(name, value)
。错误说明作为 el
传递的参数没有 setAttribute()
方法。那是因为它是一个 ElementRef 实例。
您应该传递实际的 DOM 元素:
this.renderer.setAttribute(this.elRef.nativeElement, ...)
我正在尝试在每个元素(标记为 el
)中设置一个新属性(定义为 'data-num'),引用 [ngDN](作为指令的实例NgDNDirective
)。
概念:
下面的代码解释了 NgDNDirective
的工作原理:
TS部分:
import { Directive, Input, ElementRef, Renderer2, EventEmitter } from '@angular/core'; @Directive({ selector: '[ngDN]' }) export class NgDNDirective { private dn: number = -1 @Input() set ngDN(dn: number) { this.dn = dn } @Input() set EV(ref: {ev: EventEmitter<void>}) { ref.ev.subscribe(() => { console.log('data-num:', this.dn) this.renderer.setAttribute(this.elRef, 'data-num', this.dn.toString()) }) } constructor(private elRef: ElementRef, private renderer: Renderer2) {} } @Directive({ selector: '[ngLoop]' }) export class NgLoopDirective { @Input() set ngLoop(iter_count: number) { this.container.clear() for (let i=0; i<iter_count; i++) { let ee: EventEmitter<void> = new EventEmitter<void>() let ref = {ev: ev} let ev = this.container.createEmbeddedView(this.template, {index: i, ev: ref}) ev.detectChanges() ee.emit() } } constructor(private template: TemplateRef<any>, private container: ViewContainerRef) {} }
HTML部分:
<ng-template [ngLoop]="10" let-i="index" let-ref="ev"> <a href="#" [ngDN]="i" [EV]="ref"></a> </ng-template>
问题:
经过运行测试,控制台显示如下信息:
data-num: 0
ERROR TypeError: el.setAttribute is not a function Stack trace: ../../../platform-browser/@angular/platform-browser.es5.js/DefaultDomRenderer2.prototype.setAttribute@http://localhost:8888/vendor.bundle.js:78803:13 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:66266:9 set/<@http://localhost:8888/main.bundle.js:869:17 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56260:36 ../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.__tryOrUnsub@http://localhost:8888/vendor.bundle.js:1558:13 ../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1505:17 ../../../../rxjs/Subscriber.js/Subscriber.prototype._next@http://localhost:8888/vendor.bundle.js:1445:9 ../../../../rxjs/Subscriber.js/Subscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1409:13 ../../../../rxjs/Subject.js/Subject.prototype.next@http://localhost:8888/vendor.bundle.js:1153:17 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56234:54 set@http://localhost:8888/main.bundle.js:928:17 updateProp@http://localhost:8888/vendor.bundle.js:63715:5 checkAndUpdateDirectiveInline@http://localhost:8888/vendor.bundle.js:63407:19 checkAndUpdateNodeInline@http://localhost:8888/vendor.bundle.js:64945:17 checkAndUpdateNode@http://localhost:8888/vendor.bundle.js:64884:16 debugCheckAndUpdateNode@http://localhost:8888/vendor.bundle.js:65745:38 debugCheckDirectivesFn@http://localhost:8888/vendor.bundle.js:65686:13 View_HomeComponent_4/<@ng:///AppModule/HomeComponent.ngfactory.js:121:9 debugUpdateDirectives@http://localhost:8888/vendor.bundle.js:65671:12 checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64851:5 callViewAction@http://localhost:8888/vendor.bundle.js:65216:21 execEmbeddedViewsAction@http://localhost:8888/vendor.bundle.js:65174:17 checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64852:5 callViewAction@http://localhost:8888/vendor.bundle.js:65216:21 execComponentViewsAction@http://localhost:8888/vendor.bundle.js:65148:13 checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64857:5 callViewAction@http://localhost:8888/vendor.bundle.js:65216:21 execEmbeddedViewsAction@http://localhost:8888/vendor.bundle.js:65174:17 checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64852:5 callViewAction@http://localhost:8888/vendor.bundle.js:65216:21 execComponentViewsAction@http://localhost:8888/vendor.bundle.js:65148:13 checkAndUpdateView@http://localhost:8888/vendor.bundle.js:64857:5 callWithDebugContext@http://localhost:8888/vendor.bundle.js:66071:39 debugCheckAndUpdateView@http://localhost:8888/vendor.bundle.js:65611:12 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:62782:9 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:57420:58 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:57420:13 next/<@http://localhost:8888/vendor.bundle.js:57297:100 ../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2936:17 onInvoke@http://localhost:8888/vendor.bundle.js:56503:24 ../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2935:17 ../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2686:24 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56434:54 next@http://localhost:8888/vendor.bundle.js:57297:70 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56248:36 ../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.__tryOrUnsub@http://localhost:8888/vendor.bundle.js:1558:13 ../../../../rxjs/Subscriber.js/SafeSubscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1505:17 ../../../../rxjs/Subscriber.js/Subscriber.prototype._next@http://localhost:8888/vendor.bundle.js:1445:9 ../../../../rxjs/Subscriber.js/Subscriber.prototype.next@http://localhost:8888/vendor.bundle.js:1409:13 ../../../../rxjs/Subject.js/Subject.prototype.next@http://localhost:8888/vendor.bundle.js:1153:17 ../../../core/@angular/core.es5.js/http://localhost:8888/vendor.bundle.js:56234:54 checkStable@http://localhost:8888/vendor.bundle.js:56468:13 onLeave@http://localhost:8888/vendor.bundle.js:56547:5 onInvokeTask@http://localhost:8888/vendor.bundle.js:56497:17 ../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2968:17 ../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:2736:28 ../../../../zone.js/dist/zone.js/http://localhost:8888/polyfills.bundle.js:3043:24 invokeTask@http://localhost:8888/polyfills.bundle.js:3915:9 globalZoneAwareCallback@http://localhost:8888/polyfills.bundle.js:3933:17
这意味着从NgLoopDirective
到NgDNDirective
注入的Renderer2实例没有setAttribute
方法。为什么会出现这种情况?
更多信息:
ng -v _ _ ____ _ _ / \ _ __ __ _ _ _| | __ _ _ __ / | | | | / △ \ | ' \ / _
| | | | |/ _
| '| | | | | | | / \| | | | (| | || | | (| | | | || | | | // __| ||__, |__,||__,||
____|_____|| |/ @angular/cli: 1.2.3 node: 6.11.0 os: linux x64 @angular/animations: 4.3.3 @angular/common: 4.3.3 @angular/compiler: 4.3.3 @angular/core: 4.3.3 @angular/forms: 4.3.3 @angular/http: 4.3.3 @angular/platform-browser: 4.3.3 @angular/platform-browser-dynamic: 4.3.3 @angular/router: 4.3.3 @angular/cli: 1.2.3 @angular/compiler-cli: 4.3.3 @angular/language-service: 4.3.3
您正在使用 'ngDN' 属性作为指令的选择器, 但是您还试图将该属性的值设置为循环索引的值。
使用属性作为选择器应该没问题,但您不应该尝试设置它的值。您的指令有一个名为 'ngDN':
的输入 private dn: number = -1
@Input() set ngDN(dn: number) {
this.dn = dn
}
您可能应该将其更改为:
@Input() dn: number = -1;
然后将模板更改为:
<ng-template [ngLoop]="10" let-i="index" let-ref="ev">
<a href="#" ngDN [dn]="i" [EV]="ref"></a>
</ng-template>
Renderer2#setAttribute(el, name, value)
结束调用 el.setAttribute(name, value)
。错误说明作为 el
传递的参数没有 setAttribute()
方法。那是因为它是一个 ElementRef 实例。
您应该传递实际的 DOM 元素:
this.renderer.setAttribute(this.elRef.nativeElement, ...)