0

I have an object named Gallery with several properties and methods. One of them, setCurrentPicture, removes all existing photos and videos DOM elements from gallery container before showing new photo/video. Besides my gallery stops playing video (set this to pause mode) when the user clicks on it. This is togglePlayVideo method inside the Gallery prototype. First I remove elements from DOM and then showing new content. If this is video, I add eventListener to document, use bind method.

So, in the setCurrentPicture I want to remove EventListener on video elements. Is it possible to bind this context to document inside Array.prototype.forEach method when deleting eventListener? If I saved the necessary context into new variable then I got succeed. But then I'm trying bind, my IDE is saying 'Potentially invalid usage of this'.

Code snippet:

Gallery.prototype = {
  setCurrentPicture: function(currentPhoto) {
        var self = this;

        Array.prototype.forEach.call(container.children, function(item) {
          if (item.tagName === 'VIDEO') {
            document.removeEventListener('click', self.togglePlayVideo);
          }
          if (item.tagName === 'VIDEO' || item.tagName === 'IMG') {
            container.removeChild(item);
          }
        });

       if (pictures[currentPhoto] instanceof Video) {
          var video = document.createElement('video');
          ....
          document.addEventListener('click', self.togglePlayVideo);
        }
    },
},

 togglePlayVideo: function(e) {
      if (e.target.tagName === 'VIDEO') {
        return e.target.paused ? e.target.play() : e.target.pause();
      }
    }
}

In case of addition document.addEventListener('click', self.togglePlayVideo); I can use bind instead of self: document.addEventListener('click', this.togglePlayVideo.bind(this).

Can I use bind in removeEventListener? document.removeEventListener('click', this.togglePlayVideo.bind(this);

Andrew
  • 97
  • 2
  • 9
  • 2
    What is your question? (And can you please format your code properly) – Amit Dec 22 '15 at 18:44
  • when you write something like var self = this; u are using lexacal scope. if you want to set "this" to a particular value when you call your function you can use "function_name.apply(what_supposed_to_be_this, function_arguments)". And you obviously don't need to use self = this! – Denis Dec 22 '15 at 18:46

2 Answers2

2

The best for you is to get familiar with what is "this" and what is "bind". You can do this by reading this brilliant description

and second part

To cut a long story short - when you declare a function with "this" like this:

  1. in defaul case "this" will be the Window object

    var f = function(){return this;};

    f(); //will return Window object

  2. when an object owns a link to your function like this:

    var f = function(){return this;};

    var o = {func: f};

    o.func(); // will return the "o" object becuase "this" becomes o object

  3. when you use explicit binding like call/apply you'll set this to a particular value like this:

    var f = function(){return this;};

    var obj = {};

    f.call(obj); // will return your obj

  4. and there is so called "hard binding". used like this:

    var f = function(){return this;};

    var obj1 = {num:1};

    var obj2 = {num:2};

    var boundFunc = f.bind(obj1); //now it's hardbound to obj1

    //let's try to switch this by using "call"

    boundFunc.call(obj2); // will return obj1, because it's hardbound

  5. and this can be affected when function is called with "new" keyword:

    f = function(){ this.a =1; this.b =2; };

    var obj = new f(); // will set brand new object as "this" and return it

    //so we will get {a:1, b:2} object as a result

Denis
  • 747
  • 4
  • 13
  • thanks for the answer, the problem is that I'm using method of object inside other method of those object, and inside forEach loop I have this = undefined. – Andrew Dec 22 '15 at 19:27
  • if you refer to case #4 (hardbinding) you'll see that "bind" returns a new function which is bound to a value you passed to "bind" and that bound function won't ever loose it's this. hope this helps – Denis Dec 22 '15 at 19:35
  • I'm also have tried to use static method: document.removeEventListener('click', Gallery.togglePlayVideo); But not sure that in this case event listener would be removed from particular gallery from which it has been added to document – Andrew Dec 22 '15 at 19:42
  • I have this in constructor: this.togglePlayVideo = this.togglePlayVideo.bind(this); – Andrew Dec 22 '15 at 19:48
  • 1
    You shold have a link to your callback function (var cb = function(){your_callback_code}), then you should find an element with var elem = document.getElementById('my-input') (or document.getElementsByClassName) and then to remove the listener you call elem.removeEventListener('click', callback) – Denis Dec 22 '15 at 20:18
0

I should add bind this to Array.prototype.forEach.call instead of implementing this to callback function.

 Array.prototype.forEach.call(container.children, function(item) {
          if (item.tagName === 'VIDEO') {
            document.removeEventListener('click', this.togglePlayVideo);
          }
          if (item.tagName === 'VIDEO' || item.tagName === 'IMG') {
            container.removeChild(item);
          }
        }.bind(this));

Thanks to all for the answers.

Andrew
  • 97
  • 2
  • 9