Forum Moderators: open

Message Too Old, No Replies

How to assign event to function attached to element

...preserving 'this'...

         

Dabrowski

9:54 pm on Sep 29, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I have created an object class. The class contains functions and some variables. I have attached the class to an element.

I think this is the best way to achieve what I'm trying to do, as each element can then operate independantly of each other, and I don't have to keep a huge list in the background tying elements to their variables.

For the example I'll use 2 images. They're not actually there that's not important.

function myClass( val) { 
this.myVal = val;
}

myClass.prototype.hello = function() { alert( this.val); }

var myImgs = document.getElementsByTagName( "IMG");
myImgs[0].myClass = new myClass( "FOO!");
myImgs[1].myClass = new myClass( "BAR!");

So I have a class with 1 function that pops up a value. If I call this manually it works fine. Memory wise this is ok right? There will only be 1 copy of the hello function, but 2 separate values for myVal?

The problem occurs when I'm trying to assign the function to an event, using addEvent (or anything else).

addEvent( myImgs[0], "click", WHAT SHOULD GO HERE?);

If I use this:

addEvent( myImgs[0], "click", function() { this.myClass.hello(); });

The function fires ok, but this refers to the calling function, not the element, and myVal ends up undefined. If I call the function manually the myVal is ok.

Am I over-classing this? Is there really a point in adding the functions into the class, or should I just keep the functions separate?

Fotiman

3:32 am on Sep 30, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Personally, I would suggest using the event handling capabilities of one of the JavaScript frameworks (YUI, JQuery, etc.). They let you specify the scope. For example, using YUI:

YAHOO.util.Event.on( myImgs[0], "click", myImgs[0].myClass.hello, myImgs[0].myClass, true);

Fotiman

2:35 pm on Sep 30, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Also, personally, I'm not a fan of "extending" DOM elements directly. I prefer not to dirty the DOM. What advantage do you see in attaching the objects directly to the DOM vs. storing them in your own object/array?

For example, instead of adding a myClass property to each img element, you could do something like this:

var myImgs = document.getElementsByTagName("IMG");
myObj[0] = new myClass("FOO");
addEvent(myImgs[0], "click", myObj[0].hello);

In that example, it's a very loose relationship between the element and the object you're creating, with the addEvent method tying them together. It doesn't look like you're accessing any properties of the img element so I don't see a need to create your object within the scope of an img element.

Note, this example was meant to simply show how you could store them separately. The callback to "hello" would still not have the scope of myClass, but you could do this instead:

YAHOO.util.Event.on(myImgs[0], "click", myObj[0].hello, myObj[0], true );

Dabrowski

10:36 pm on Sep 30, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



They let you specify the scope

So how does that work then?

I am particularly interested to know that, it would be very handy for something else I'm working on....

Although now I know what I'm looking for I can probably Google it.

advantage do you see in attaching the objects directly to the DOM vs. storing them in your own object/array?

Not having my own object/array, and then having to find this particular object within that array.

You have to admit, knowing that 'this' will always mean the object in question, that is a whole lot easier?

It doesn't look like you're accessing any properties of the img element

That was just an example. I plan to attach to INPUT tags for the other script in progress. So it would access the name and value properties, and also store it's own validation settings.

Fotiman

3:03 pm on Oct 1, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



JavaScript has methods call(this[,arg1[,arg2[, ...]]]) and apply(this[,args]). These methods let you call a function and specify what the 'this' keyword will refer to. So, if your addEvent method takes in an object that's meant to have the scope, then addEvent could create a wrapper function that returns a call() or apply() on your callback method, passing the scope object as the first parameter. For example:

function addEvent(el, ev, cb, scopeObj) {
//...
if (!scopeObj) {
scopeObj = el;
}
var wrapper = function() {
return cb.call(scopeObj);
});
addListener(el, ev, wrapper);

Note, that is a very bare bones example. I didn't perform any cross browser checks (this example will fail in IE). But hopefully that gives you an understanding of the basic concept.


You have to admit, knowing that 'this' will always mean the object in question, that is a whole lot easier?

That's one thing that's great about Yahoo's Event Utility. When you attach your event listeners, you can specify an object reference to pass as a parameter and/or to be scoped as "this".

Dabrowski

5:54 pm on Oct 1, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I see. Very handy and simple to use, I'd never heard of those functions before.

So what's the difference between call and apply? And why won't that example work in IE? You're going to tell me now MS decided not to implement those 2 functions?!

Fotiman

6:12 pm on Oct 1, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Call takes individual parameters as the arguments, apply takes an array as the 2nd paramter which represents the arguments.

function foo(a, b) {
alert('#'+a+'#:*'+b+'*');
}
foo.call(window, 'x', 'y');
foo.apply(window, ['x', 'y']);

The reason my earlier example wouldn't work is because I called addListener... I would need to add some logic to determine whether I could call addListener or if I had to call attachEvent, since one method only works in standards compliant browsers and the other only works in IE.

[edited by: Fotiman at 6:13 pm (utc) on Oct. 1, 2008]

Dabrowski

9:11 pm on Oct 1, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Call takes individual parameters as the arguments, apply takes an array as the 2nd paramter which represents the arguments

Yeah I saw that when I looked them up. Seems strange to have 2 functions though that do exactly the same thing. Nevermind.

because I called addListener

Oh I didn't spot that. I thought there was a problem with using call itself.

Thanks again for that one Foti!