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

问题描述 投票:12回答:3

由于没有模板,在指令中监听子元素事件的最佳方法是什么?有没有可能与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))
angular angular2-directives
3个回答
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
投票

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

// 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


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,因此选择器每次都会运行,并且还会设置该函数,但由于它是一个静态函数,您只需覆盖它就不会出现太多的性能问题。

© www.soinside.com 2019 - 2024. All rights reserved.