angular:调用el.setAttribute会导致错误

时间:2017-09-16 22:38:03

标签: javascript angular typescript renderer setattribute

我试图在每个元素(标记为el)中设置一个新属性(定义为&#39; data-num&#39; ),指的是< strong> [ngDN] (作为指令NgDNDirective的实例)。

概念:

以下代码说明了NgDNDirective的工作方式:

  1. 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) {}
    
    }
    
  2. HTML部分:

    <ng-template [ngLoop]="10" let-i="index" let-ref="ev">
      <a href="#" [ngDN]="i" [EV]="ref"></a>
    </ng-template>
    
  3. 问题:

    运行测试后,控制台会显示以下信息:

      

    data-num:0

         

    错误TypeError:el.setAttribute不是函数堆栈跟踪:   ../../../platform-b​​rowser/@angular/platform-b​​rowser.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   集/&LT; @ 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   组@ 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 /&LT; @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   下一个/&LT; @ 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   下@ 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

    这意味着从NgLoopDirectiveNgDNDirective注入的Renderer2实例没有setAttribute方法。为什么会这样?

    进一步的信息:

      

    ng -v       _ _ ____ _ _ / \ _ __ __ _ _ _ | | __ _ _ __ / | | | | /△\ | &#39; \ / _ | | | | |/ _ | &#39;的 | | | | | | | / \ | | | | ( | | | | | |   ( | | | | | | | | | / / __ | | | __,| __, | | __, | |
      ____ | _____ | |                  | / @ 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-b​​rowser:4.3.3 @ angular / platform-b​​rowser-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

2 个答案:

答案 0 :(得分:7)

Renderer2#setAttribute(el, name, value)最终致电el.setAttribute(name, value)。错误说的是,作为el传递的参数没有setAttribute()方法。那是因为它是一个ElementRef实例。

您应该传递实际的DOM元素:

this.renderer.setAttribute(this.elRef.nativeElement, ...)

答案 1 :(得分:0)

您使用'ngDN'属性作为指令的选择器, 但您也尝试将该属性的值设置为循环索引的值。

使用属性作为选择器应该没问题,但是你不应该试图设置它的值。您的指令有一个名为'ngDN'的输入:

dataframe.index = pd.to_datetime(dataframe.index)

您应该将其更改为:

  private dn: number = -1

  @Input() set ngDN(dn: number) {
    this.dn = dn
  }

然后将模板更改为:

@Input() dn: number = -1;