473,834 Members | 1,879 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Set event handler to global object's method...?

Why doesn't the below code work?

I'm trying to create a global object and set an event handler to one of its
methods. The function is called, but the object's mTest property is
undefined.

(What I'm trying to do is make a general-purpose solution for the situation
where you have a list box with several associated form elements. When the
element values are changed, you want to update the value of the selected
list option, and when the list selection changes, you want to update the
form elements. So here you could have a "watcher" object that is constructed
with a bunch of element names and handles that stuff without any custom
code.)

Joakim Braun

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<script type="text/javascript">

function cWatcher(){

this.mTest = "Testing";
this.wire = cWatcher_Wire;
this.changeFunc = cWatcher_Change d;
}
function cWatcher_Wire( inFormName,
inElementName){

document.forms[inFormName].elements[inElementName].onchange =
this.changeFunc ;

}

function cWatcher_Change d(){

alert("Changed, test=" + this.mTest);

}
</script>
</head>

<body>
<form id="form1" action="">
<select id="obj1">
<option value="1">Data</option>
<option value="2">More data</option>
</select>
</form>

<script type="text/javascript">

window.gWatcher = new cWatcher();
window.gWatcher .wire("form1"," obj1");
</script>
</body>
</html>
Jul 23 '05 #1
7 2284
On Wed, 22 Dec 2004 22:51:27 +0100, Joakim Braun
<jo**********@j fbraun.removeth is.com> wrote:
Why doesn't the below code work?

I'm trying to create a global object and set an event handler to one of
its methods. The function is called, but the object's mTest property is
undefined.
Read the following slowly. I always find it difficult to word properly. :(

In the case of using the this operator in a function, it is set by the
caller when the function is called. That is, the caller determines what
this refers to when the call is made.

When you assign a function reference to the property of an object and then
call that function as a method, the this operator will refer to said
object:

var myObject = new Object();
function myFunction() {}

/* myFunction is a property of the global object so when the this
* operator is used, it will refer to the global object.
*/
myFunction();

/* myFunction is now called as a method of the object, myObject.
* Here the this operator will refer to myObject.
*/
myObject.myMeth od = myFunction;
myObject.myMeth od()

So, when you assign a method from one object to another, the this operator
won't point to the original object, it will point to the one it was called
from.

One way around this is to use a closure and reserve the this operator for
getting the form element.

function Watcher() {
/* Define data here as local variables. */
var test = 'Testing...';

function change() {
/* When this function is called as a result of the change
* event, the this operator will refer to the form control
* that triggered the event.
*/
alert('Changed (test=' + test + ')');
}

this.wire = function(form, element) {
document.forms[form].elements[element].onchange = change;
};
}

var obj = new Watcher();
obj.wire('form1 ', 'obj1');

[snip]
function cWatcher(){

this.mTest = "Testing";
this.wire = cWatcher_Wire;
this.changeFunc = cWatcher_Change d;
}
function cWatcher_Wire( inFormName,
inElementName){

document.forms[inFormName].elements[inElementName].onchange =
this.changeFunc ;

}

function cWatcher_Change d(){

alert("Changed, test=" + this.mTest);

}
Those two functions should be added via the prototype:

function cWatcher() {
this.mTest = 'Testing';
}
cWatcher.protot ype.wire = function(form, element) {
document.forms[form].elements[element].onchange = this.changeFunc ;
};
cWatcher.protot ype.changeFunc = function() {
alert("Changed, test=" + this.mTest);
};

Obviously, that will still suffer from the original problems. It was just
a technical suggestion.

[snip]
window.gWatcher = new cWatcher();
window.gWatcher .wire("form1"," obj1");


The 'window' isn't necessary.

var gWatcher = new cWatcher();
gWatcher.wire(' form1', 'obj1');

The var keyword in this instance isn't either; I just think it's good form.

[snip]

Hope that helps,
Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #2
"Michael Winter" <M.******@bluey onder.co.invali d> skrev i meddelandet
news:opsjfpb8fx x13kvk@atlantis ...

<snip>
Read the following slowly. I always find it difficult to word properly. :(
You're doing fine.

<snip>
One way around this is to use a closure and reserve the this operator for
getting the form element.

function Watcher() {
/* Define data here as local variables. */
var test = 'Testing...';

function change() {
/* When this function is called as a result of the change
* event, the this operator will refer to the form control
* that triggered the event.
*/
alert('Changed (test=' + test + ')');
}

this.wire = function(form, element) {
document.forms[form].elements[element].onchange = change;
};
}

var obj = new Watcher();
obj.wire('form1 ', 'obj1');
OK, I think I get that, a bit vaguely. Couldn't figure out how to establish
the right "this" context. And this allows for having several of these things
around, each with its own "member variables", right?

<snip>
Those two functions should be added via the prototype:

function cWatcher() {
this.mTest = 'Testing';
}
cWatcher.protot ype.wire = function(form, element) {
document.forms[form].elements[element].onchange = this.changeFunc ;
};
cWatcher.protot ype.changeFunc = function() {
alert("Changed, test=" + this.mTest);
};


<snip>

Why? (I mean, they got called anyway. Or didn't they? Is there any reason
why functions should be treated differently than variables?)

(I'll find that out, so don't answer if it's laborious to explain. I'm just
longing for C++...)

Joakim Braun

Jul 23 '05 #3
On Thu, 23 Dec 2004 10:43:31 +0100, Joakim Braun
<jo**********@j fbraun.removeth is.com> wrote:
"Michael Winter" <M.******@bluey onder.co.invali d> skrev i meddelandet
news:opsjfpb8fx x13kvk@atlantis ...
[snip]
function Watcher() {
/* Define data here as local variables. */
var test = 'Testing...';

function change() {
/* When this function is called as a result of the change
* event, the this operator will refer to the form control
* that triggered the event.
*/
alert('Changed (test=' + test + ')');
}

this.wire = function(form, element) {
document.forms[form].elements[element].onchange = change;
};
}

var obj = new Watcher();
obj.wire('form1 ', 'obj1');


OK, I think I get that, a bit vaguely.


It works on the principle that inner functions like change, and the
anonymous function expression assigned to this.wire, can access variables
in surrounding scopes. It avoids the problem where the this operator won't
refer to the Watcher object by providing direct access to the data.

A technical discussion of closures can be found in the FAQ notes
(<URL:http://www.jibbering.c om/faq/faq_notes/closures.html>) . Another
related text can be found on Douglas Crockford's website
(<URL:http://www.crockford.c om/javascript/private.html>).
Couldn't figure out how to establish the right "this" context.
Could you elaborate? Perhaps show what you've tried and explain what you
expected.
And this allows for having several of these things around, each with its
own "member variables", right?
Absolutely. Each time a Watcher object is created, any "private" data
(like test) will be unique to that object.
Those two functions should be added via the prototype:

function cWatcher() {
this.mTest = 'Testing';
}
cWatcher.protot ype.wire = function(form, element) {
document.forms[form].elements[element].onchange =
this.changeFunc ;
};
cWatcher.protot ype.changeFunc = function() {
alert("Changed, test=" + this.mTest);
};


Why?


Why via the prototype? As I said, it's a technical correction; using the
prototype is the "proper" way to add methods to achieve the result you
were aiming form. Also, it means you aren't adding addition identifiers to
the global namespace.
Is there any reason why functions should be treated differently than
variables?)


I'm afraid I'm not sure I follow[1]. What special treatment do you see?

[snip]

Mike
[1] I've probably forgotten what I thought when I first read about this
stuff, so please forgive my current inability to relate.

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #4


Joakim Braun wrote:
"Michael Winter" <M.******@bluey onder.co.invali d> skrev i meddelandet
news:opsjfpb8fx x13kvk@atlantis ...
Those two functions should be added via the prototype:

function cWatcher() {
this.mTest = 'Testing';
}
cWatcher.protot ype.wire = function(form, element) {
document.forms[form].elements[element].onchange = this.changeFunc ;
};
cWatcher.protot ype.changeFunc = function() {
alert("Changed, test=" + this.mTest);
};

Why? (I mean, they got called anyway. Or didn't they? Is there any reason
why functions should be treated differently than variables?)


It is a matter of style and efficiency, in a language like Java or C++
all instances created with
new Watcher()
would share the same methods but in JavaScript if you do
function Watcher () {
this.changeFunc = function () { ... }
}
then each time you create a
new Watcher()
a new function is created and assigned to the changeFunc property.
If you use
Watcher.prototy pe.changeFunc = function () { ... }
then all instances created with
new Watchwer()
share that single function object.
--

Martin Honnen
http://JavaScript.FAQTs.com/
Jul 23 '05 #5
"Martin Honnen" <ma*******@yaho o.de> skrev i meddelandet
news:41******** *************** @newsread4.arco r-online.net...
Joakim Braun wrote:
"Michael Winter" <M.******@bluey onder.co.invali d> skrev i meddelandet
news:opsjfpb8fx x13kvk@atlantis ...

Those two functions should be added via the prototype:

function cWatcher() {
this.mTest = 'Testing';
}
cWatcher.protot ype.wire = function(form, element) {
document.forms[form].elements[element].onchange = this.changeFunc ;
};
cWatcher.protot ype.changeFunc = function() {
alert("Changed, test=" + this.mTest);
};

Why? (I mean, they got called anyway. Or didn't they? Is there any reason why functions should be treated differently than variables?)


It is a matter of style and efficiency, in a language like Java or C++
all instances created with
new Watcher()
would share the same methods but in JavaScript if you do
function Watcher () {
this.changeFunc = function () { ... }
}
then each time you create a
new Watcher()
a new function is created and assigned to the changeFunc property.
If you use
Watcher.prototy pe.changeFunc = function () { ... }
then all instances created with
new Watchwer()
share that single function object.


I see, thanks.

Joakim Braun

Jul 23 '05 #6
"Michael Winter" <M.******@bluey onder.co.invali d> skrev i meddelandet
news:opsjgtolgs x13kvk@atlantis ...
<snip useful discussion>
Couldn't figure out how to establish the right "this" context.


Could you elaborate? Perhaps show what you've tried and explain what you
expected.


I was thinking in terms of implicit (and "invisible" , to the programmer)
"this" pointers passed to C++ class member functions. (for instance, would
someElement.onc hange=someFunct ion pass an implicit "this" to someFunction,
and how to change the "this" into some other object than the someElement)

<snip>
Those two functions should be added via the prototype: <snip> cWatcher.protot ype.changeFunc = function() {
alert("Changed, test=" + this.mTest);
};


Why?


Why via the prototype? As I said, it's a technical correction; using the
prototype is the "proper" way to add methods to achieve the result you
were aiming form. Also, it means you aren't adding addition identifiers to
the global namespace.
Is there any reason why functions should be treated differently than
variables?)


I'm afraid I'm not sure I follow[1]. What special treatment do you see?


this.mSomething = "variable value" (or var something = "value", plus "inner
functions" that can access the something)
vs
cSomeObject.pro totype.mSomethi ng = function(){...}

But Martin's reply explained that.

Thanks again.

Joakim Braun

Jul 23 '05 #7
On Sun, 26 Dec 2004 10:25:41 +0100, Joakim Braun
<jo**********@j fbraun.removeth is.com> wrote:

[snip]
I was thinking in terms of implicit (and "invisible" , to the programmer)
"this" pointers passed to C++ class member functions. (for instance,
would someElement.onc hange=someFunct ion pass an implicit "this" to
someFunction, and how to change the "this" into some other object than
the someElement)
Every function has an associated this value, but that value changes based
on how the function is called. When an event listener assigned like this:

someElement.onc hange = someFunction

is called, the this value for someFunction would be someElement.

You can change what is used for the this value through the call method:

func.call(obj, arg, ...);

The function, func, would be called as if it were a method of the object,
obj, and is passed the remaining arguments. Unfortunately, the call method
was added as late as JScript 5.5 (though earlier to JavaScript), so you'll
need to emulate it for the majority of users with IE 5.5 or earlier:

if(Function.pro totype && ('function' != Function.protot ype.call)) {
Function.protot ype.call = function(obj, arg) {
var prop = '__call', ret;
while('undefine d' != typeof obj[prop]) {prop += prop;}
obj[prop] = this;
ret = obj[prop](arg);
delete obj[prop];
return ret;
};
}

Clearly, this only lets you pass one argument to the function, but that's
easily changed. There is one other complication, though. If obj is an
element reference, the use of the delete operator will cause an error in
IE. The only option here is to use a fixed temporary property name and
hope that there are no conflicts:

if(Function.pro totype && ('function' != Function.protot ype.call)) {
Function.protot ype.call = function(obj, arg) {
var prop = '__call';
obj[prop] = this;
return obj[prop](arg);
};
}

[snip]
this.mSomething = "variable value" (or var something = "value", plus
"inner functions" that can access the something)
vs
cSomeObject.pro totype.mSomethi ng = function(){...}


Oh, I see. In my mind, that had nothing to do with variables which is
where to confusion arose.

[snip]

Mike
Seasons Greetings

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #8

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

Similar topics

7
49589
by: Pavils Jurjans | last post by:
Hallo, I have been programming for restricted environments where Internet Explorer is a standard, so I haven't stumbled upon this problem until now, when I need to write a DOM-compatible code. The question is about best practices for passing parameters to an event function. I have, say, the following HTML:
10
3610
by: tony kulik | last post by:
This code works fine in ie and opera but not at all in Mozilla. Anybody got a clue as to how to get it right? <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <script language="JavaScript" type="text/javascript"> function show(that) { if (box.style.visibility=='hidden') { that.style.visibility = 'visible'}; }
6
2343
by: Amir Hardon | last post by:
I am dynamically adding rows to a table, and each row have a button which removes it. I have successfully implemented this for mozilla but I'm having troubles with IE, here is how I did it: Each new row's id is an index number, each button's name is the row's id, and I'm adding this function as the click event listener for the button: function removeline(event){ var row=document.getElementById("row" + event.target.name);
2
8362
by: Breeto | last post by:
Can anyone please tell me why the following doesn't work... using System; using System.Web; namespace AspTests {
10
2523
by: Sean Dockery | last post by:
I have the following HTML file that I've been using for testing... <html> <head> <script type="text/javascript"> <!-- function handleWindowLoad() { var items = ; for (var i = 0; i < 11; i++) { items = "item" + (i + 1);
4
9701
by: mflll | last post by:
I am looking into the different techniques of handling arrays of edit boxes in Java Script. The first program below works fine. However, are there better ways of doing this, where the person writing the JavaScript doesn't have to pass the index in the "onChange" event name. I thought that one might be able to use "this.value" or compare this as
5
3869
by: james | last post by:
Hello, I am having a little trouble creating an event handler for a context menu toolstripmenuitem. I've seen various tutorials and so on, but I keep getting a bit stuck! So far I have a second class defining the eventargs I want to use: public class ApptEventArgs : EventArgs{ public int ApptUID; public String ApptOp;
2
2378
by: Robert | last post by:
Hello javascript group readers, I have a question regarding how to prevent memory leaks in Internet Explorer when using closures. I already knew about the circular reference problem, and until now was able to prevent memory leak problems. But I needed to store DOM elements and can't solve it anymore. So I search the group archive to see if I missed any valuable information. I found some interesting articles, but somehow could not apply...
2
2663
by: Ralph | last post by:
Hi I don't understand why it's not working: function schedule(imTop){ this.tdImagesTop = imTop; } schedule.prototype.selectEl = function() { alert(this.tdImagesTop);
0
9799
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9646
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 synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
10548
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 most users, this new feature is actually very convenient. If you want to control the update process,...
1
7758
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6954
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 into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5627
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5794
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4427
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
3
3081
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.