Posts Tagged ‘jQuery’

Posted by admin at 5 August 2009

Category: programming

Tags: ,

If you are not a seasoned Javascript developer (like myself), and you start writing Javascript classes which include jQuery event bindings, you may become stumped on the issue I am about to describe. On the contrary you are most likely more intelligent than I and realize that what you are trying to do is wrong and you consult the jQuery documentation to find the answer within the first 2 minutes of stumbling upon this problem.

Anyways, the issue at hand is setting up event bindings via jQuery inside of a class. This is easier explained with a simple code example. Take the following class:

function Page()
{
	var msg  = 'weeeeeeee';

	this.bindElements = function(elementOne, elementTwo)
	{
		$(elementOne).click(function() {
			this.elementOneStuff('yoyo');
		});
		$(elementTwo).click(this.elementTwoStuff);
	}

	this.elementOneStuff = function(a)
	{
		alert(a);
	}

	this.elementTwoStuff = function()
	{
		alert(this.msg);
	}
}

var p = new Page();
p.bindElements('#btnOne', '#btnTwo');

When you instantiate a new Page object and invoke the bindElements method you get barked at:

this.elementOneStuff() is not a function.

My initial reaction was that it was a scoping issue with my privileged class methods. After changing the architecture of my class to use public methods the same issue was there.

Solution / Answer

The this keyword that is being used in both of the callbacks will refer to the DOM element that dispatched the event…. not an instance of the Page Class. This is in fact the correct behavior as it will almost always be what is desired.

jQuery.bind( type, [data], fn ) to the rescue! Straight from the jQuery documentation:

data (Optional) Object
Additional data passed to the event handler as event.data

We can simply pass an object as the data parameter to the bind method and then invoke our class methods through event.data. So the updated, correct code would be:

function Page()
{
	var msg  = 'weeeeeeee';

	this.bindElements = function(elementOne, elementTwo)
	{
		$(elementOne).bind('click', this, function(evt) {
			evt.data.elementOneStuff('yoyo');
		});
		$(elementTwo).bind('click', this, function(evt) {
			evt.data.elementTwoStuff();
		});
	}

	this.elementOneStuff = function(a)
	{
		alert(a);
	}

	this.elementTwoStuff = function()
	{
		alert(this.msg);
	}
}

This took me more time to figure out than I would like to admit. I am posting this in the hopes that it saves someone some time and frustration.