Динамическое добавление прослушивателя событий в Angular 2



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



у меня есть настроенный компонент. При нажатии на определенный элемент в шаблоне я хочу добавить прослушиватель для mousemove к другому элементу того же шаблона. Затем я хочу удалить этот прослушиватель при нажатии на третий элемент.



Я вроде как получил эту работу, просто используя простой Javascript, чтобы захватить элементы и затем вызов стандарта addEventListener() но мне было интересно, есть ли еще"Angular2.0" способ сделать это, что я должен смотреть.



спасибо за любые советы :)

509   3  

3 ответов:

рендер был осужден в угловой 4.0.0-радиоуправляемый.1, Прочитайте обновление ниже

The angular2 way использовать listen или listenGlobal С рендерер

например, если вы хотите добавить событие click к компоненту, вы должны использовать Renderer и ElementRef (это дает вам также возможность использовать ViewChild или все, что извлекает nativeElement)

constructor(elementRef: ElementRef, renderer: Renderer) {

    // Listen to click events in the component
    renderer.listen(elementRef.nativeElement, 'click', (event) => {
      // Do something with 'event'
    })
);

можно использовать listenGlobal что будет дать вам доступ к document,body и т. д.

renderer.listenGlobal('document', 'click', (event) => {
  // Do something with 'event'
});

обратите внимание, что с бета-версии.2 как listen и listenGlobal возвращает функцию для удаления прослушивателя (см. последние изменения раздел из журнала изменений для бета-версии.2). Это делается во избежание утечек памяти в больших приложениях (см. #6686).

поэтому, чтобы удалить прослушиватель, который мы добавили динамически, мы должны назначить listen или listenGlobal к переменной, которая будет содержать возвращенную функцию, а затем мы выполняем оно.

// listenFunc will hold the function returned by "renderer.listen"
listenFunc: Function;

// globalListenFunc will hold the function returned by "renderer.listenGlobal"
globalListenFunc: Function;

constructor(elementRef: ElementRef, renderer: Renderer) {

    // We cache the function "listen" returns
    this.listenFunc = renderer.listen(elementRef.nativeElement, 'click', (event) => {
        // Do something with 'event'
    });

    // We cache the function "listenGlobal" returns
    this.globalListenFunc = renderer.listenGlobal('document', 'click', (event) => {
        // Do something with 'event'
    });
}

ngOnDestroy() {
    // We execute both functions to remove the respectives listeners

    // Removes "listen" listener
    this.listenFunc();

    // Removs "listenGlobal" listener
    this.globalListenFunc();
}

здесь plnkr С примером работы. Пример содержит использование listen и listenGlobal.

С помощью RendererV2 с угловой 4.0.0-rc.1+ (Renderer2 с 4.0.0-rc.3)

  • 25/02/2017:Renderer был осужден, теперь мы должны использовать RendererV2 (см. строку ниже). Смотрите commit.

  • 10/03/2017:RendererV2 была переименована в Renderer2. Смотрите последние изменения.

RendererV2 больше listenGlobal функции для глобальных событий (документ, тело, окно). Он имеет только listen функция, которая обеспечивает обе функции.

для справки, я копирую и вставляю исходный код рендерера DOM реализация, так как она может измениться (да, это угловой!).

listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean):
      () => void {
    if (typeof target === 'string') {
      return <() => void>this.eventManager.addGlobalEventListener(
          target, event, decoratePreventDefault(callback));
    }
    return <() => void>this.eventManager.addEventListener(
               target, event, decoratePreventDefault(callback)) as() => void;
  }

как вы можете видеть, теперь он проверяет, передаем ли мы строку (документ, тело или окно), и в этом случае он будет использовать внутренний

Я Асо нахожу это чрезвычайно запутанным. как указывает @EricMartinez Renderer2 listen () возвращает функцию для удаления слушателя:

ƒ () { return element.removeEventListener(eventName, /** @type {?} */ (handler), false); }

если я добавляю слушателя

this.listenToClick = this.renderer.listen('document', 'click', (evt) => {
      alert('Clicking the document');
    })

Id ожидайте, что моя функция выполнит то, что я намеревался, а не полную противоположность, которая удаляет слушателя.

// I´d expect an alert('Clicking the document'); 
this.listenToClick();
// what you actually get is removing the listener, so nothing...

в данном сценарии Itd на самом деле имеет больше смысла называть его так:

// Add listeners
let unlistenGlobal = this.renderer.listen('document', 'click', (evt) => {
  console.log('Clicking the document', evt);
})

let removeSimple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => {
  console.log('Clicking the button', evt);
});

должна быть веская причина для этого, но в моем мнение его очень обманчиво и не интуитивно.

вот мое решение:

я создал библиотеку с угловой 6. Я добавил общий компонент commonlib-header, который используется как в наружном применении.

Примечание serviceReference который класс (вводится в компонент constructor(public serviceReference: MyService) использует commonlib-header), который содержит stringFunctionName способ:

<commonlib-header
    [logo]="{ src: 'assets/img/logo.svg', alt: 'Logo', href: '#' }"
    [buttons]="[{ index: 0, innerHtml: 'Button', class: 'btn btn-primary', onClick: [serviceReference, 'stringFunctionName', ['arg1','arg2','arg3']] }]">
    </common-header>

компонент библиотеки запрограммирован следующим образом. Динамическое событие добавляется в onClick(fn: any) способ:

export class HeaderComponent implements OnInit {

 _buttons: Array<NavItem> = []

 @Input()
  set buttons(buttons: Array<any>) {
    buttons.forEach(navItem => {
      let _navItem = new NavItem(navItem.href, navItem.innerHtml)

      _navItem.class = navItem.class

      _navItem.onClick = navItem.onClick // this is the array from the component @Input properties above

      this._buttons[navItem.index] = _navItem
    })
  }

  constructor() {}

  ngOnInit() {}

  onClick(fn: any){
    let ref = fn[0]
    let fnName = fn[1]
    let args = fn[2]

    ref[fnName].apply(ref, args)
  }

многоразовая header.component.html:

<div class="topbar-right">
  <button *ngFor="let btn of _buttons"
    class="{{ btn.class }}"
    (click)="onClick(btn.onClick)"
    [innerHTML]="btn.innerHtml | keepHtml"></button>
</div>

Comments

    Ничего не найдено.