如何在指令中听取子元素事件?

时间:2016-11-17 15:11:16

标签: angular angular2-directives

由于没有模板,在指令中监听子元素事件的最佳方法是什么? HostListener可以吗?如果没有,还有其他办法吗?

还有这个类似的问题:How to listen for child event from parent directive in Angular2,但建议的方法并不能解决我的问题,因为我的指令和子元素不在同一个模板中(指令在主机上)

干杯!

编辑#1

这就是我目前正在做的事情(必须有更好的方法):

首先将ElementRef注入我的指令:

constructor(private elView: ElementRef) {}

然后用jQuery(或普通JS)绑定:

$(this.elView.nativeElement)
.on('drag', '#childId', this.slide.bind(this))

3 个答案:

答案 0 :(得分:7)

如果您要收听的事件是冒泡的本机DOM事件,那么您可以使用@HostListener()

@HostListener('click', ['$event'])
handleClick(event) {
  // handle event
}

如果它们是子组件的输出,您可以查询它们并订阅它们的输出

@ContentChildren(ChildComponent) children:QueryList<ChildComponent>;

ngAfterContentInit() {
  this.children.toArray().forEach((item) => {
    item.someOutput.subscribe(...);
  });
}

或者您可以使用您在问题中链接的答案中使用的方法。

答案 1 :(得分:1)

您可以考虑让您的组件通过服务类相互通信。

// service class
class Service {
  private someEventSource = new Subject();
  public someEvent = this.someEventSource.asObservable();

  public invokeAnEvent (data: string) {
    this.someEventSource.next(data);
  }
}

// parentComponent class
Service.someEvent.subscribe(data => {
  console.log(data);
});

// childComponent class
Service.invokeAnEvent('some data to pass');

来自Angular文档:
https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

答案 2 :(得分:0)

我对这个问题的解决方案是在根组件ngAfterContentChecked中添加并选择我所有相关的元素并添加事件。例如:

  ngAfterContentChecked() {
    //console.log('MASTER ngAfterContentChecked')
    let rgx = /^[0-9,\.]+$/;
    let preventNonNumber = e => {
      //let v = (e.target as HTMLInputElement).value
      if (
        // Allow: Delete, Backspace, Tab, Escape, Enter
        [46, 8, 9, 27, 13].indexOf(e.keyCode) !== -1 || 
        (e.keyCode === 65 && e.ctrlKey === true) || // Allow: Ctrl+A
        (e.keyCode === 67 && e.ctrlKey === true) || // Allow: Ctrl+C
        (e.keyCode === 86 && e.ctrlKey === true) || // Allow: Ctrl+V
        (e.keyCode === 88 && e.ctrlKey === true) || // Allow: Ctrl+X
        (e.keyCode === 65 && e.metaKey === true) || // Cmd+A (Mac)
        (e.keyCode === 67 && e.metaKey === true) || // Cmd+C (Mac)
        (e.keyCode === 86 && e.metaKey === true) || // Cmd+V (Mac)
        (e.keyCode === 88 && e.metaKey === true) || // Cmd+X (Mac)
        (e.keyCode >= 35 && e.keyCode <= 39) // Home, End, Left, Right
      ) {
        return;  // let it happen, don't do anything
      }

      if (rgx.test(e['key']) == false) {
        e.preventDefault();
      }
    };
    let inputs = document.querySelectorAll('label-input[numberOnly] input, cbx-label-input[numberOnly] input')
    //console.log(inputs)
    inputs.forEach(i => (i as HTMLInputElement).onkeydown = preventNonNumber)
  }

请注意,每次触摸输入都会触发ngAfterContentChecked,因此选择器将再次运行,并同时设置函数,但是由于它是一个静态函数,因此您只需重写就不会有太多性能问题。