web-dev-qa-db-ja.com

Angular2、HostListener、どのように要素をターゲットにできますか?クラスに基づいてターゲットを設定できますか?

Angular2では、HostListenerデコレータ内の要素をどのようにターゲットにできますか?

@HostListener('dragstart', ['$event'])
    onDragStart(ev:Event) {
        console.log(ev);
    }

@HostListener('document: dragstart', ['$event'])
    onDragStart(ev:Event) {
        console.log(ev);
    }

@HostListener('myElement: dragstart', ['$event'])
    onDragStart(ev:Event) {
        console.log(ev);
    }

@HostListener('myElement.myClass: dragstart', ['$event'])
    onDragStart(ev:Event) {
        console.log(ev);
    }

最初の2つの作業。私が試した他のことは、EXCEPTION: Unsupported event target undefined for event dragstartを発生させます

だから、ターゲット要素に実装できますか?どうやって?

30
GWorking

@HostListener()は、グローバルイベントターゲットとしてwindowdocument、およびbodyのみをサポートします。それ以外の場合は、コンポーネントのHost要素のみをサポートします。

38

受け入れられた答えは実際に問題を解決するのに役立たないので、ここに解決策があります。

これを実現するためのより良い方法は、ディレクティブを作成することです。この方法では、任意の要素にディレクティブを追加でき、リスナーはこの特定の要素に対してのみトリガーします。

例えば:

@Directive({
   selector: "[focus-out-directive]"
})
export class FocusOutDirective {
   @Output() onFocusOut: EventEmitter<boolean> = new EventEmitter<false>();

   @HostListener("focusout", ["$event"])
   public onListenerTriggered(event: any): void {
       this.onFocusOut.emit(true);
   }
}

次に、このリスナーを適用するHTML要素にディレクティブセレクター(この場合はfocus-out-directive)を追加し、コンポーネントでトリガーする関数を指定します。

例:

<input type='text' focus-out-directive (onFocusOut)='myFunction($event)'/>

24
Googs

グローバルリスナーのより良い方法は@hostliternerだと思いますが、いくつかの要素をターゲットにしたい場合はこのようにすることができます

<div (event)="onEvent($e)"></div>

angularコンポーネントで

onEvent($e) { //do something ... }
4
Rey

要素で聞く:

import { Renderer2 } from '@angular/core';
...
constructor(private renderer: Renderer2) {}

// Get this.myElement with document.getElement... or ElementRef 

ngOnInit() {
  // scroll or any other event
  this.renderer.listen(this.myElement, 'scroll', (event) => {
  // Do something with 'event'
  console.log(this.myElement.scrollTop);
});

}

3
alex351
import { Directive, ElementRef, OnInit, Output, EventEmitter} from '@angular/core';

    @Directive({
          selector: '[checkClick]'
        })

        export class checkClickDirective implements OnInit {

        @Output() public checkClick = new EventEmitter();

        constructor(private _el: ElementRef) { }

        @HostListener('click', ['$event.target']) public onClick(targetElement) {

            const checkClick = this._el.nativeElement.contains(targetElement);

            (checkClick)?this.checkClick.emit(true):this.checkClick.emit(false);
          }
        }
2
Noufal PP

Googsが指摘したように、受け入れられた答えは質問に答えますが、解決策を見つける助けにはなりません。

さまざまな画面サイズの通知のリストを取得するために、すでに@HostListenerにあった機能を使用する方法が必要だったため、アレックスの答えに基づいて作成しました。

たとえば、私のアプリでは、通知ページはモバイルでは独自のルートを持っていますが、上記のタブレットや画面サイズのサイドバーに存在するため、@HostListenerは使用できません。サイドバーではなく、ページ全体の下部。

代わりに、<div>を調べ、必要なものに興味を持って添付しました。したがって、次のコード:

attachListenerToContainer() {
    let elementToListenTo = this.ele ? this.ele : 'window';

    this.renderer.listen(elementToListenTo, 'scroll', (event) => {
      if(!this.reachedBottom) {
        if((getHeight(this.ele) + getScrollTop(this.ele)) >= getOffset(this.ele)) {
          this.reachedBottom = true;
          this.getNextNotificationsPage();
        }
      }
    });

    function getScrollTop(ele) {
      return ele ? ele.scrollTop : window.scrollY;
    }
    function getHeight(ele) {
      return ele ? ele.clientHeight : window.innerHeight;
    }
    function getOffset(ele) {
      return ele ? ele.scrollHeight : document.body.offsetHeight;
    }
  }

this.eleは、興味のあるコンテナdivで、タブレット用のngAfterViewInit()ライフサイクルフックで検索します。その要素が見つからない場合は、代わりにウィンドウを使用します-@HostListenerを効果的にエミュレートします

また、ここで私が探していた方法、私の場合は、私が欲しかったコンテナ要素です:

this.ele = document.getElementsByClassName('notifications')[0]; 
0
Katana24