473,545 Members | 2,115 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Object method as event listener

I want each instance of an object to be able to listen for input events.
When the event occurs, a method of the object should be called, such
that "this" is in scope and refers to the object instance.

Is this possible?

Example:

function MyConstructor(e lement)
{
//element is some HTML element
this.addListene rs(element);

this.foo = "Bar";

return this;
}

MyConstructor.p rototype.addLis teners = function(elemen t)
{
element.addEven tListener("keyp ress", this.doSomethin g, true);
}

MyConstructor.p rototype.doSome thing = function(e)
{

alert(this.foo. length); //Error: this.foo has no properties

alert(this);
//shows the HTML element that triggered the event
}

Is there any way to get "this" to refer to the object in the event listener?

Thanks,
Jeremy
Oct 16 '06 #1
6 6849
aka
No problem:
function MyConstructor(e lement)
{
//element is some HTML element
this.addListene rs(element);

this.foo = "Bar";
// not necessary
//return this;
}

MyConstructor.p rototype.addLis teners = function(elemen t)
{
// don't take native DOM function, it's not supported by IE5/6,
take a workaround, for example:
// http://aka-fotos.de/research/js/prototype_extended.js < take the
last both functions
//element.addEven tListener("keyp ress", this.doSomethin g, true);
addEventListene r(element, "keypress", this.doSomethin g, true);
// make a backlink
element._obj = this;
}
// it's not necessary any more to make a object function because
THIS is the html element
MyConstructor./*prototype.*/doSomething = function(e)
{

alert(this._obj .foo.length); // should work now

alert(this._obj );
//shows the MyConstructor object now
}
That should work, I do it very often in OO and UI programming.

Andi

Oct 16 '06 #2
Jeremy wrote:
I want each instance of an object to be able to listen for input events.
When the event occurs, a method of the object should be called, such
that "this" is in scope and refers to the object instance.
All function objects have a this value that is established when the
function is called, not when you declare it. You can modify the object
used for the this value using the function's apply() or call() methods.

The usual method is to use the this keyword to create a reference back
to the object when you attach the event, not try to get a reference to
the object at some later time. You might also consider simply adding
the property to a prototype object at an appropriate point in the scope
chain and avoid munging the this keyword altogether.

Is this possible?

Example:

function MyConstructor(e lement)
{
//element is some HTML element
this.addListene rs(element);

this.foo = "Bar";

return this;
}

MyConstructor.p rototype.addLis teners = function(elemen t)
{
element.addEven tListener("keyp ress", this.doSomethin g, true);
Is this only for W3C browers? You seem to be ignoring IE's attachEvent.
}

MyConstructor.p rototype.doSome thing = function(e)
{

alert(this.foo. length); //Error: this.foo has no properties
Because the foo property belongs to the (possibly anonymous) object
that was used to attach the event, which is not what the this keyword
will refer to when the event calls the function.

In Gecko browsers, the this keyword will refer to the HTML element that
the event is attached to. In IE, it will refer to the window/global
object.
alert(this);
//shows the HTML element that triggered the event
Or the window object in IE. Try replacing the body of the addListeners
function with:

var obj = this;
element.onkeypr ess = function(){
obj.doSomething .apply(obj);
}

But the closure will likely cause a memory leak in IE. If you really
want to use attachEvent, try:

var obj = this;
if (element.addEve ntListener){
element.addEven tListener(
'keyup',
function() {obj.doSomethin g.apply(obj)},
true
);
} else if (element.attach Event){
element.attachE vent(
'onkeyup',
function() {obj.doSomethin g.apply(obj)}
);
}

Again you have a closure/memory leak issue in IE.

}

Is there any way to get "this" to refer to the object in the event listener?
Another strategy is to add a property to the element that points back
to the object and use the event to find the target/source element and
hence get the foo property:

MyConstructor.p rototype.addLis teners = function(elemen t)
{
element.srcObj = this;
if (element.addEve ntListener){
element.addEven tListener('keyu p', this.doSomethin g, true);
} else if (element.attach Event){
element.attachE vent('onkeyup', this.doSomethin g);
}
}

MyConstructor.p rototype.doSome thing = function(e)
{
var e = e || window.event;
var tgt = e.target || e.srcElement;
alert(tgt.srcOb j.foo);
}

--
Rob

Oct 17 '06 #3
Jeremy wrote:
I want each instance of an object to be able to listen for input events.
When the event occurs, a method of the object should be called, such
that "this" is in scope and refers to the object instance.

Is this possible?
Yes ! With the help and magic of 'apply', this can be done. Here's how
it can be done (the bindAsEventList ener function was taken from the
Prototype library at http://prototype.conio.net/) :
<div id="test1">Clic k me 1</div>
<div id="test2">Clic k me 2</div>

<script type="text/javascript">

Function.protot ype.bindAsEvent Listener = function(object ) {
var args = [];
for (var i = 0; i < arguments.lengt h; i++)
args.push(argum ents[i]);

var __method = this;
var object = args.shift();
return function(event) {
return __method.apply( object, [( event ||
window.event)].concat(args).c oncat(arguments ));
}
};

var Events = {

clickHandler: function(event) {

alert( this.id + ' was clicked !' );

}

};

var test1 = document.getEle mentById('test1 ');
var test2 = document.getEle mentById('test2 ');

test1.onclick = Events.clickHan dler.bindAsEven tListener(test1 );
test2.onclick = Events.clickHan dler.bindAsEven tListener(test2 );
As you can see, the bindAsEventList ener ensures that 'this' inside the
function always refers to the object passed as parameter.

Hope this helps.

-Yanick

Oct 17 '06 #4
BTW : you would normally only worry about memory leaks when repeatedly
manipulating the same object property with such code
(bindAsEventLis tener), so it's mostly a matter of choosing wisely how
to use what when.

Oct 17 '06 #5
RobG wrote:
Is this only for W3C browers? You seem to be ignoring IE's attachEvent.
Initially, I'm targeting standards, not I.E. If IE7 fails to support
the W3 model I might consider hacking in attachEvent support, but this
is a personal project so I can support whatever I wish and I prefer to
target standards.

Thanks for the thorough explanation. All that replied have been quite
helpful.

Jeremy
Oct 17 '06 #6
Yanick wrote:
Jeremy wrote:
I want each instance of an object to be able to listen for input events.
When the event occurs, a method of the object should be called, such
that "this" is in scope and refers to the object instance.

Is this possible?

Yes ! With the help and magic of 'apply', this can be done. Here's how
it can be done (the bindAsEventList ener function was taken from the
Prototype library at http://prototype.conio.net/) :

<div id="test1">Clic k me 1</div>
<div id="test2">Clic k me 2</div>

<script type="text/javascript">

Function.protot ype.bindAsEvent Listener = function(object ) {
var args = [];
for (var i = 0; i < arguments.lengt h; i++)
args.push(argum ents[i]);

var __method = this;
var object = args.shift();
return function(event) {
return __method.apply( object, [( event ||
window.event)].concat(args).c oncat(arguments ));
}
};

var Events = {
clickHandler: function(event) {
alert( this.id + ' was clicked !' );
The value of this.id isn't necessarily the id of the element that was
clicked on, it is the id of the element reference that was passed to
the function. It would be better example to have:

clickHandler: function(event) {
var tgt = event.target || event.srcElemen t;
if (tgt.nodeType != 1) tgt = tgt.parentNode;
alert(
'You clicked on ' + tgt.id + '\nbut '
+ 'this.id is: ' + this.id
);
}

and modify the attach code as suggested below.

}
};

var test1 = document.getEle mentById('test1 ');
var test2 = document.getEle mentById('test2 ');

test1.onclick = Events.clickHan dler.bindAsEven tListener(test1 );
test2.onclick = Events.clickHan dler.bindAsEven tListener(test2 );
It might have been a better example to use:

test1.onclick = ...(test2);
test2.onclick = ...(test1);

To show how the this value had been modified.

As you can see, the bindAsEventList ener ensures that 'this' inside the
function always refers to the object passed as parameter.
But it seems a long way around, considering you passed the object to
the function in the first place and could just grabbed it from the
arguments object instead of messing with apply and the this value.

The following:

var Events ={};
Events.showID = function (){
alert(this.id);
}
var test3 = document.getEle mentById('test3 ')
test3.onclick = Events.showID;
achieves the same result in much less code - provided you have an
element with id='test3' of course. :-)
--
Rob

Oct 18 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
17188
by: Joe Kelsey | last post by:
When you use addEventListener (or addEvent in IE) to call an object method, does it call it with the correct this parameter? The ECMAScript reference has a lot to say about the caller using Function.prototype.call or Function.prototype.apply and passing the correct this pointer for the context, but how does addEventListener determine the...
14
9557
by: Michael Winter | last post by:
In an attempt to answer another question in this group, I've had to resort to calling the DOM method, Node.removeChild(), using a reference to it (long story...). That is, passing Node.removeChild. In Opera (7.23/Win), the call appears to do nothing - the node remains - but no errors are shown. In Netscape (7.0/Win), an exception results....
6
1682
by: b.dam | last post by:
I'm trying to do the following: function row() { this.selected = false; this._el = document.createElement("TR"); this._el.attachEvent("onClick", this.rowClick); } row.prototype.rowClick = function() { this.selected = true;
1
5197
by: Jim P. | last post by:
I'm having trouble returning an object from an AsyncCallback called inside a threaded infinite loop. I'm working on a Peer2Peer app that uses an AsyncCallback to rerieve the data from the remote peer. I have no problem connecting the peers and streaming Network Streams. When the incoming data is finished recieving, I act upon it. This...
4
1858
by: Luke Matuszewski | last post by:
Here are some questions that i am interested about and wanted to here an explanation/discussion: 1. (general) Is the objectness in JavaScript was supported from the very first version of it (in browsers) ? What about the new syntax of creating a object using { 'propName1':'propValue1', 'propName2':'propValue2', 'propName3':{ /* another object...
16
2878
by: anonymous.user0 | last post by:
The way I understand it, if I have an object Listener that has registered as a listener for some event Event that's produced by an object Emitter, as long as Emitter is still allocated Listener will stay alive. Is this correct? If this is correct, I've got a problem. Let's say I've got an object Customer that has an PurchaseList...
2
1800
by: darthghandi | last post by:
I am creating a listener class that listens for incoming connections. When I get an incoming connection, I want to signal an event to happen and pass that connected socket to a different thread for the real work. I want to continue to listen for more connections. So is the socket I pass with the delegate a reference or a value? I thought...
3
3103
by: Greg A | last post by:
What I am unsuccessful at doing is adding the event listener to an object in memory which isn't referencing an HTML element: // DATA OBJECT CONSTRUCTOR function dataObject(id){ // EVENT this.addEventListener("error",function(event){this.err(event)},true); // METHOD
6
4351
by: lochru45 | last post by:
I'm running the following javascript with no problem in FireFox: var multiGallery = { init: function(options){ this.overlay = new Element('div').setProperty('id','lbOverlay').injectInside(document.body).addEvent('click',this.close.bind(this)); this.gallery = new Element('div').setProperty('id','gallery').injectInside(document.body);...
0
7401
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7656
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
7808
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7423
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
7757
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
5972
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
0
4945
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
1
1884
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1014
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.