“Imagination is more important than knowledge. For while knowledge defines all we currently know and understand, imagination points to all we might yet discover and create.” - Albert Einstein


Run JavaScript Event-Handler in Another Context

When a JavaScript function is called by an event such as "onclick" or "onmouseover", it runs in the context of the calling DOM element. What if you do not want this event-handler to run under the context of the DOM element but instead you would like to run it under a custom object that you have created? Let us have the following example.

Listing 1
function MessageHandle(divObject, message) 
{
    this.Message = message;
    this.OnClick = function() 
    {
        alert(this.Message);
    }

    divObject.attachEvent('onclick', this.OnClick);
}

var divObject = document.getElementById("_divMain");
var _h = new MessageHandle(divObject, "Hello World!");
We are creating a function called MessageHandle that is later on used to instantiate a MessageHandle object at line 13. In the constructor of MessageHandle, we can see that the message ("Hellow World!") is stored in the property Message (line 3) and OnClick function is attached to the divObject's onclick event (line 9). The OnClick event handler simply shows an alert box showing the message "Hello World!".

So far so good. Now if you run this code and the click event of _divMain is triggered then you will get not the message "Hello World" but instead the message "undefined". What went wrong? Though OnClick is declared as a method of the object MessageHandle, the function will always run in the context of the calling object which is in this case _divMain and not the MessageHandle object. The "this" in line 6 is actually referring to _divMain. So how do we make sure that OnClick will run in the context of MessageHandle? We will create a new function and use the JavaScript's function apply().

Listing 2
function RunHandlerInContextOf(Context, Handler){
    return function() { 
             return Handler.apply(Context); 
         }
}
The function RunHandlerInContextOf has two parameters Context and Handler. Handler is the event-handler to execute and Context is the object context that Handler will run under. Notice that RunHandlerInContextOf function returns a function that is a wrapper to the event-handler call at line 3.

Now here is our updated JavaScript code.

Listing 3
function RunHandlerInContextOf(Context, Handler){
    return function() { 
             return Handler.apply(Context); 
         }
}

function MessageHandle(divObject, message) 
{
    this.Message = message;
    this.OnClick = function() 
    {
        alert(this.Message);
    }

    divObject.attachEvent('onclick', RunHandlerInContextOf(this,this.OnClick));
}

var divObject = document.getElementById("_divMain");
var _h = new MessageHandle(divObject, "Hello World!");
Here is a JavaScript cross-browser utility I created for attaching event-handlers and gives you an option to run the event-handler in the default context or specify another object as the context.

Listing 4
var CoolScriptingUtil = {
    //cross-browser attach event.
    //Element - is the object where eventhandler will be attached to
    //EventString    - is the event name to handle of Element
    //Handler is a function pointing to the event handler
    //Context is what context the Handler will be executed
    attachEvent: function(Element, EventString, Handler, Context) {
        if (typeof (Context) != 'undefined' && Context != null) {
            if (Element.addEventListener) // W3C DOM
                Element.addEventListener(EventString, CoolScriptingUtil.ContextOf(Context, Handler), false);
            else if (Element.attachEvent) // IE DOM
                Element.attachEvent('on' + EventString, CoolScriptingUtil.ContextOf(Context, Handler));
            else
                alert('Unable to attach to event ' + EventString + ' of ' + Element.toString());
        } else {
            if (Element.addEventListener) // W3C DOM
                Element.addEventListener(EventString, Handler, false);
            else if (Element.attachEvent) // IE DOM
                Element.attachEvent('on' + EventString, Handler);
            else
                alert('Unable to attach to event ' + EventString + ' of ' + Element.toString());
        }
    },

    //Returns a function that executes [Method] in the context of [ThisObj]
    ContextOf: function(ThisObj, Method) {
        return function() { Method.apply(ThisObj); };
    }
}
To use this utility we can now replace the command on listing 3 line 15 "divObject.attachEvent('onclick', RunHandlerInContextOf(this,this.OnClick));" with the following.

Listing 5
CoolScriptingUtil.attachEvent(divObject, 'click', this.OnClick, this);
The fourth parameter is optional. When you remove the fourth parameter, the event-handler will run in the default context.

Labels: , , ,

 Subscribe to feed

1 Responses to “Run JavaScript Event-Handler in Another Context”

  1. # Anonymous Anonymous

    thanks, turned out to be very useful to me  

Post a Comment


John Eric Sobrepena

John Eric Sobrepena
Hi, I am an I.T. professional who loves technology. I am right now into Android development. I am also a subject matter expert on C#, ASP.NET, WPF and Silverlight. Photography is one of my many hobbies.
Bookmark and Share

Type your Email

Follow me on Twitter.

Flickr Photostream



 Subscribe to feed


Powered by Blogger



© 2006 IdeaSparx | Blogger Templates by GeckoandFly.
No part of the content or the blog may be reproduced without prior written permission.