I'm trying to set a new attribute (defined as 'data-num') within each element (labeled as el
) referring to [ngDN] (as an instance of the directive NgDNDirective
).
Concept:
The code below explains how NgDNDirective
is intended to work:
TS part:
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 part:
<ng-template [ngLoop]="10" let-i="index" let-ref="ev"> <a href="#" [ngDN]="i" [EV]="ref"></a> </ng-template>
Problem:
After running the test, the console shows me the following information:
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
This means that the injected instance of Renderer2 from NgLoopDirective
to NgDNDirective
, comes without setAttribute
method. Why does this occur?
Further informations:
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
Renderer2#setAttribute(el, name, value)
ends up callingel.setAttribute(name, value)
. What the error says is that the argument passed asel
does not have asetAttribute()
method. And that is because it is an ElementRef instance.You should be passing the actual DOM element: