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);
    }

Две первые работы. Любая другая вещь, которую я пробовал, вызывает EXCEPTION: Unsupported event target undefined for event dragstart

Итак, могу ли я реализовать его для целевого элемента? Как?

Ответы

Ответ 1

@HostListener() поддерживает только window, document и body как глобальные целевые объекты, в противном случае он поддерживает только элемент хоста компонентов.

Ответ 2

Поскольку принятый ответ на самом деле не помогает решить проблему, вот решение.

Лучший способ добиться этого - создать директиву, таким образом вы можете добавить директиву к любому элементу, который вы хотите, и слушатели будут запускаться только для этого конкретного элемента.

Например:

@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)'/>

Ответ 3

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);
          }
        }

Ответ 4

Я думаю, что лучший способ для глобального слушателя - @hostliterner, но если вы хотите настроить таргетинг на какой-то элемент, вы можете сделать это следующим образом.

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

в вашем угловом компоненте

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

Ответ 5

Прослушать элемент:

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);
});

}

Ответ 6

Как указывает Гугс, принятый ответ действительно отвечает на вопрос, но не помогает найти решение.

Я основывался на ответе alex, так как мне нужен был способ использовать функции, которые у меня уже были в моем @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 - это интересующий меня контейнерный контейнер, который я ищу в ngAfterViewInit() жизненного цикла ngAfterViewInit() для планшета и выше. Если я не могу найти этот элемент, я использую вместо этого окно - эффективно эмулируя @HostListener

Также - вот как я искал, в моем случае, элемент контейнера, который я хотел:

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

Ответ 7

Вы также можете настроить таргетинг на любой элемент без @hostlistener и добавлять необходимые события следующим образом

import { AfterViewInit, Component, ElementRef} from '@angular/core';

constructor(private elementRef:ElementRef) {}

ngAfterViewInit() {
  this.elementRef.nativeElement.querySelector('my-element')
                                .addEventListener('click', this.onClick.bind(this));
}

onClick(event) {
  console.log(event);
}