web-dev-qa-db-ja.com

ディレクティブで子要素イベントをリッスンする方法は?

テンプレートがないので、ディレクティブで子要素イベントをリッスンする最良の方法は何ですか? HostListenerで可能ですか?そうでない場合、他の方法はありますか?

この同様の質問もあります: Angular2の親ディレクティブから子イベントをリッスンする方法 しかし、私のディレクティブと子要素が同じテンプレート(ディレクティブ)にないため、提案されたアプローチは私の問題を解決しませんホスト上にあります)。

乾杯!

編集#1

これは私が現在それをしている方法です(より良い方法がなければなりません):

最初にElementRefを私のディレクティブに挿入します:

constructor(private elView: ElementRef) {}

次に、jQuery(またはプレーンJS)とバインドします。

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

聞きたいイベントがバブルするネイティブDOMイベントである場合は、@HostListener()を使用できます。

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

それらが子コンポーネントの出力である場合、それらをクエリして、それらの出力をサブスクライブできます。

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

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

または、質問でリンクした回答で使用されているアプローチを使用できます。

7

コンポーネントをサービスクラスを介して互いに通信させることを検討するかもしれません。

// 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#!#bidirection-service

この問題に対する私の解決策は、ルートコンポーネント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が起動されるため、セレクターは毎回実行され、関数の設定も実行されますが、静的関数であるため、オーバーライドするだけでパフォーマンスの問題はそれほど発生しません。

0
bresleveloper