View Full Version : Unobtrusive classes & 'this'

03-12-2009, 07:28 PM
Hi, I'm trying to write an unobtrusive javascript class which makes it so that when you click in a textbox, a dropdown is shown next to it (it'll eventually become something like a predictive textbox).

The problem I'm having is that I'm losing reference to the class whenever I give an element within it an event handler and 'this' is referring to the element that raised the event (as it should), but I want a reference to the class instance.

My html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<script type="text/javascript" src="Global.js"></script>
<script type="text/javascript" src="example.js"></script>
<script type="text/javascript" src="ExampleClass.js"></script>

<input type="text" value="" id="clickThis" />
<select id="selectThis" style="display: none;">
<option value="1">Value 1</option>
<option value="2">Value 2</option>
<option value="3">Value 3</option>


My javascript file for the page

addEvent(window, "load", initExample);

function initExample()
var textbox = document.getElementById("clickThis");
var dropdown = document.getElementById("selectThis");

var test = new ExampleClass(textbox, dropdown);

My javascript class

function ExampleClass(textbox, dropdown) {
this.textbox = textbox;
this.dropdown = dropdown;

addEvent(this.textbox, 'click', showDropdown);

function showDropdown()
this.dropdown.style.display = "block";

Gloal.js (its just John Resigs add and remove event functions)

function addEvent( obj, type, fn ) {
if ( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
obj.attachEvent( 'on'+type, obj[type+fn] );
} else
obj.addEventListener( type, fn, false );

function removeEvent( obj, type, fn ) {
if ( obj.detachEvent ) {
obj.detachEvent( 'on'+type, obj[type+fn] );
obj[type+fn] = null;
} else
obj.removeEventListener( type, fn, false );

Basically, when I say this.dropdown.display.. I want it to point at the classes .display property, not the actual textbox which raised the event.

Thanks in advance for any help :)

Old Pedant
03-13-2009, 12:03 AM
The problem is, of course, that indeed the this can *ONLY* refer to the object which *raises* the event.

And then your other problem is that you have no "connection" from those event-raising objects *to* your ExampleClass instances.

An obvious answer would be to simply add a property to the textbox that refers to the ExampleClass object you created for it. But if I recall correctly, this does not work in all browsers.

So another way would be to use an associative array to "map" the eventable-objects to the connected ExampleClass objects. And of course all arrays in JS are naturally associative arrays, so that's easy enough.

I admit I've never tried using object references as the "keys" in a JS array, but there's a first time for everything:

var ExampleEventObjects = new Array( );

function ExampleClass(textbox, dropdown) {
this.textbox = textbox;
this.dropdown = dropdown;
addEvent(this.textbox, 'click', showDropdown);
ExampleEventObjects(this.textbox) = this;

function showDropdown()
ExampleEventObject(this).dropdown.style.display = "block";

Utterly untested and never done anything like it, but seems to make sense to me. If it doesn't work with object references for keys, you could always use the object ID's instead and then have to use this.id to do the "lookup".