2

I am trying to change custom icon of video, when video is toggled(Play/Pause).

ngAfterViewInit() {
 const vdoCont = document.querySelector('.video-player');
 const vdo = vdoCont.querySelector('video');
    vdo.addEventListener('play', () => {
     console.log(this) // Here "this" refers to typescript class
     this.updateVdoIcon(this);
    });
    vdo.addEventListener('pause', () => {
     console.log(this) // Here "this" refers to typescript class
     this.updateVdoIcon(this);
    });
}

updateVdoIcon(videoElment: any) {
    console.log(videoElment); // Expecting this to be video element instead of typescript class
  }

I have tried to change arrow functions to JavaScript function, but here I cannot use my "updateVdoIcon" function.

vdo.addEventListener('play', function() {
      this.updateVdoIcon(this); // Property 'updateVdoIcon' does not exist on type 'HTMLVideoElement'
});

I know I can use anonymous function (shown below) and update icon there, but what if I have lot of code which I want to separate in a function

vdo.addEventListener('play', function() {
 this.paused ? console.log('Play icon') : console.log('Pause icon')
});
SuleymanSah
  • 17,153
  • 5
  • 33
  • 54
Sameer
  • 4,758
  • 3
  • 20
  • 41

4 Answers4

2

You can try this way, using ElementRef you can access the element and then bind the event.

Source code is from the : https://stackoverflow.com/a/41610950/9380944 answer.

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);
}
Ankit Prajapati
  • 2,670
  • 2
  • 12
  • 22
2

When the event listener handler is call, it's not called under the scope of the Component. So this doesn't return the component, but the control element instead.

You need to bind your listener with this.

vdo.addEventListener('play', (function() {
      this.updateVdoIcon(this);
}).bind(this));

See document here.


You can make it clearer by separating it to a function call onClick.

onClick() {
  this.updateVdoIcon(this);
}

initialize() {
  vdo.addEventListener('play', this.onClick.bind(this));
}

Or, you can capture this as the component and pass to the event listener.

let self = this;

vdo.addEventListener('play', function() {
      self.updateVdoIcon(this);
});
Daniel Tran
  • 6,083
  • 12
  • 25
1

You can pass the event.currentTarget in the callback, which would be your element where you defined the event listener:

vdo.addEventListener('play', (event) => {
     this.updateVdoIcon(event.currentTarget);
});

In your snippet, the this would be the lexical this in the arrow function. It captures the the this contextfrom the lexical scope i.e. the class instance.

Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
1

Here is your solution

ngAfterViewInit() {
const vdoCont = document.querySelector('.video-player');
const vdo = vdoCont.querySelector('video');
const that = this;
   vdo.addEventListener('play', function(){
    console.log(this) // Here "this" refers to typescript class
    that.updateVdoIcon(this);
   });
   vdo.addEventListener('pause', function(){
    console.log(this) // Here "this" refers to typescript class
    that.updateVdoIcon(this);
   });

}

updateVdoIcon(videoElment: any) { console.log(videoElment); // Expecting this to be video element instead of typescript class }

Ankur Patel
  • 478
  • 3
  • 6