Search code examples
javascriptunit-testingthismodule-pattern

javascript module How to get the current object ( this referencing something else )?


I'm noticing that this references something else inside a function that I added as event listener. I read this informative resource and a few questions on stackoverflow but I don't know how to apply it to my case (I'm quite new to the "oop" and the module pattern in javascript so I'm a bit lost).

Here is my little module:

var myModule = myModule || ( function() {
  // Adds event listener for all browsers
  // see http://stackoverflow.com/a/6348597 
  function addEvent( element, event, listener ) {
    // IE < 9 has only attachElement
    // IE >= 9 has addEventListener
    if ( element.addEventListener ) {
      return element.addEventListener( event, listener, false );
    } else if ( element.attachElement ) {
      return element.attachElement( "on" + event, listener );
    }
  }

  return {
    init: function() {
      // Add event listeners
      addEvent(
        document.getElementById( "myElementId" ),
        "click",
        this.processMyElement
      );
      addEvent(
        document.getElementById( "myOtherElementId" ),
        "click",
        this.processMyOtherElement
      );
    },
    hideElementById: function( elementId ) {
      document.getElementById( elementId ).style.display = "none";
    },
    showElementById: function( elementId ) {
      document.getElementById( elementId ).style.display = "block";
    },
    processMyElement: function() {
      this.hideElementById( "myElementId" );
      this.showElementById( "myOtherElementId" );
    },
    processMyOtherElement: function() {
      // Do something else...
    }
  };
}() );

The thing is that this which I use to call hideElementById in processMyElement is referencing to the element I added an eventListener to, and not to the current object.

I tried a few things without success:

  • removing the return in addEvent,
  • using var that = this as a private property of the module (placed in the module before the addEvent definition) and using that in processMyElement
  • using apply in the init method but it (obviously) calls processMyElement when adding the listener to the element

Could anyone help me with this? I tried a few things but I cannot see how to do it better...

PS: I try to build testable code, that's why I had those hideElementById and showElementById methods, in order to separate various functionalities (that may be quite clumsy actually but that's where I am ATM...).


Solution

  • There are (more than) a couple of common ways to get the correct this binding. For example, you can use a closure:

      var that = this;
      addEvent(
        document.getElementById( "myOtherElementId" ),
        "click",
        function () {
          that.processMyOtherElement();
        }
      );
    

    Or you could use bind:

      addEvent(
        document.getElementById( "myOtherElementId" ),
        "click",
        this.processMyOtherElement.bind(this)
      );
    

    https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

    The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

    Which one you use would depend on other factors.