为什么我无法在组件的构造函数中访问模板DOM元素

时间:2017-08-02 15:26:28

标签: angular typescript rxjs reactive-programming

从RxJS开始,想要创建一个简单的按钮点击流,所以我只是这样做:

export class AppComponent {

    button : HTMLElement = document.querySelector('button');

    refreshClickStream$ = Observable.fromEvent(this.button, 'click')
       .subscribe();

    constructor(){
    }  

但在控制台中收到该错误...

也尝试过这样:

  clicked(e) {
    return Observable.fromEvent(e.target, 'click')
    .do(console.log)
       .subscribe();
  }

但是第一次点击后我在控制台中没有输出。第二次单击后,我得到一个MouseEvent对象。第三次单击后,我得到两个MouseEvent对象。第四次点击后,我得到其中的三个等等。所以我认为点击事件处理程序与RxJS fromEvent函数重复。

非常欢迎任何解释。

1 个答案:

答案 0 :(得分:1)

您有以下设置:

AppComponent 
   template: '<button>some button</button>'
   button : HTMLElement = document.querySelector('button');

在转换为JavaScript时,放在类中的顶级代码将用作构造函数的主体:

class AppComponent {
   constructor() {
       let HTMLElement = document.querySelector('button');
   }
}

现在,Angular遍历组件树,并逐个为每个组件创建一个包含DOM节点的视图。因此,它首先为托管app-component的组件创建一个视图。它为它生成一个DOM主机元素,然后调用AppComponent构造函数。此时,带有按钮DOM元素AppComponent的视图尚未创建。因此,当执行构造函数时,您尝试查找尚未创建的DOM元素按钮。

为了做你想做的事,你可以使用任何生命周期钩子。要获取更多信息,请阅读Difference between Constructor and ngOnInit的答案。

除了这个问题,我还建议使用@ViewChild作为DOM查询和ngOnInit生命周期钩子,如下所示:

template: `<button #b>...</button>`
...
class AppComponent {
   @ViewChild('b') button;

   ngOnInit() {
       this.refreshClickStream$ = Observable.fromEvent(this.button, 'click').subscribe();
   }
}