By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,568 Members | 1,713 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,568 IT Pros & Developers. It's quick & easy.

Events and the window keyword

P: n/a
Is it bad form to use the global window variable to reference an event
handlers window?

Like so:

function SortableTable() {

oFilterAdd = this.document.createElement("button");
oFilterAdd.setAttribute("type", "button");
oFilterAddText = this.document.createTextNode("Add");
oFilterRemoveText = this.document.createTextNode("Remove");
document.appendChild(oFilterAdd);
oFilterAdd.addEventListener("click", this.addOnclick, false);
}

SortableTable.prototype.addOnclick = function () {

this.removeChild(window.oFilterAddText);
this.appendChild(window.oFilterRemoveText);
}

I realize i could pass the addOnClick function by reference such as:

oFilterAdd.addEventListener("click", this.addOnclick(), false);

to avoid using the window variable. In that case, 'this' would refer to
the window object not the add buttons click method. However, I would
like to pass addOnClick by value as given in the first example.

Thanks,
Derek Basch

Jul 23 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Derek Basch wrote:

[Subject:] Events and the window keyword

Just so you know, there is no window keyword. It is just a
(well-known) global variable that refers back to the global object.
Is it bad form to use the global window variable to reference an event
handlers window?
Not really, though you might say that it's nicer to write something like

var global = this;

in global scope. You can now refer to the global object without
relying on DOM 0 behaviour. More to the point though, I see no reason
for you to refer to the global object directly, anyway.

[snip]
oFilterAdd = this.document.createElement("button");
The this operator seems unnecessary here, and elsewhere, in this
function (unless you have a document member, of course).
oFilterAdd.setAttribute("type", "button");
Unless you're using XHTML (true XHTML, not XHTML served as HTML), it's
preferable to use the shortcut properties:

oFilterAdd.type = 'button';

[snip]
this.removeChild(window.oFilterAddText);
this.appendChild(window.oFilterRemoveText);
Why do you feel the need to use the window global? Simply
oFilterAddText or oFilterRemoveText will be sufficient (unless you
have variables with those names higher in the scope chain, which I
doubt is true).
I realize i could pass the addOnClick function by reference such as:

oFilterAdd.addEventListener("click", this.addOnclick(), false);


That would be a function call, not a reference. In any case, it
wouldn't matter: addOnclick would be called as a member of oFilterAdd.

[snip]

A completely different approach would be to use a closure, avoiding
globals altogether (which is arguably better):

function SortableTable() {
var filter = document.createElement('button'),
addText = document.createTextNode('Add'),
removeText = document.createTextNode('Remove');

function listener(e) {
this.removeChild(addText);
this.appendChild(removeText);
}

filter.type = 'button';
document.appendChild(filter);
filter.addEventListener('click', listener, false);
}

However, something feels very odd about this whole question so I
assume you've omitted a lot of details.

Mike

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

P: n/a
Michael Winter wrote:
Derek Basch wrote:
oFilterAdd = this.document.createElement("button");
The this operator seems unnecessary here, and elsewhere, in this
function (unless you have a document member, of course).


Yes, there was a document member. I have removed it though because it
was redundant.
this.removeChild(window.oFilterAddText);
this.appendChild(window.oFilterRemoveText);


Why do you feel the need to use the window global? Simply
oFilterAddText or oFilterRemoveText will be sufficient (unless you
have variables with those names higher in the scope chain, which I
doubt is true).


Right again. I had already declared them as global variables so it was
also redundant.
I realize i could pass the addOnClick function by reference such as:
oFilterAdd.addEventListener("click", this.addOnclick(), false);


That would be a function call, not a reference. In any case, it
wouldn't matter: addOnclick would be called as a member of

oFilterAdd.

Right again. It should have read:

oFilterAdd.addEventListener("click", this.addOnclick, false);
A completely different approach would be to use a closure, avoiding
globals altogether (which is arguably better):


After reading all I could stomach about closure I worked up an example
that uses your example of using closure to reference properties and an
example of what I would like to do using prototyping.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
</head>
<body>

<form id="form">
</form>

<script type="text/javascript">

function SortableTable() {
var filter = document.createElement('button');
var filter_2 = document.createElement('button');
var form = document.getElementById("form");
var addText = document.createTextNode('Add');
var removeText = document.createTextNode('Remove');
var addText_2 = document.createTextNode('Add');
var removeText_2 = document.createTextNode('Remove');

filter.type = 'button';
filter_2.type = 'button';
form.appendChild(filter);
form.appendChild(filter_2);
filter.appendChild(addText);
filter_2.appendChild(addText_2);

//listener function reference is obtained as a private method using
closure
filter.addEventListener('click', listener, false);
//proto_listener is a public method of SortableTable and a reference
// cannot be obtained using closure.
filter_2.addEventListener('click', this.proto_listener, false);

function listener(e) {
//this references button object
//addText/removeText are accesable as private properties
// via closure
this.removeChild(addText);
this.appendChild(removeText);
}
}

SortableTable.prototype.proto_listener = function (e) {
//this references button object
//addText_2/removeText_2 are not accesable as private properties
//via closure so an error is generated
this.removeChild(addText_2);
this.appendChild(removeText_2);
}

st = new SortableTable();

</script>
</body>
</html>

It seems that I will need to pass the scope of the SortableTable
instance to the proto_listener function.

I found this:

http://jibbering.com/faq/faq_notes/closures.html#clObjI

which seems to be an excellent solution to the scoping issues. It is a
bit of a mind bender (for me at least) but here is my own workup of the
authors example.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
</head>
<body>

<script type="text/javascript">

function associateObjWithEvent(obj, methodName){
//obj is the SortableTable instance
return (function(e){
e = e||window.event;
//this refers to the event object
//when onclick occurs obj and methodName
//are still available because of closure
return obj[methodName](e, this);
});
}

function SortableTable(elementId){
this.property = "foo"
var el = document.getElementById(elementId);
if(el){
el.onclick = associateObjWithEvent(this, "doOnClick");
}
}

SortableTable.prototype.doOnClick = function(event, element){
//this scope has not changed so this.property is available
alert(this.property);
alert(element);
element.id = "new_text"
alert(element.id);
}

p = document.createElement("p");
p.id = "text";
text = document.createTextNode("text");
document.body.appendChild(p);
p.appendChild(text);
obj = new SortableTable("text");

</script>
</body>
</html>

Thanks for all the help and feel free to rip apart my logic and
terminology.

Derek Basch

Jul 23 '05 #3

P: n/a
Derek Basch wrote:

[snip]
After reading all I could stomach about closure
Closures aren't necessarily the easiest things to understand. At least
not at first. The specifics delve deep into the language and touch on
information that isn't really explained anywhere outside of the
language specification (a link is in the FAQ[1]). To make matters
worse, the specification is badly written in that it's difficult to
comprehend. It's not really surprising that closures aren't used that
often (intentionally) "in the wild".
I worked up an example that uses your example of using closure to
reference properties and an example of what I would like to do
using prototyping.
[snipped example]

It seems fine, aside from the problem you acknowledged. I'm surprised
my suggestion was useful - I thought I was missing too much information.

Is there any particular reason why you want to use prototyping? It is
for extensibility, or for some other purpose?
It seems that I will need to pass the scope of the SortableTable
instance to the proto_listener function.


To continue using "private" data, you have little choice but to use a
closure of some kind. It is impossible to directly "privilege" a
prototyped member. However, it is still possible to delegate to a
prototyped member:

function SortableTable(id) {
/* Create a reference to the SortableTable object.
* This can be used in cases where the this operator
* will refer to something other than a SortableTable
* instance.
*/
var instance = this,
/* Initialise the rest of our private data. */
filter = document.createElement('button'),
addText = document.createTextNode('Add'),
removeText = document.createTextNode('Remove'),
element = document.getElementById(id);

/* Create a "privileged" function which can access
* the "private" data above and pass it to an
* unprivileged method.
*/
function listener() {
instance.doOnClick(this, removeText, addText);
}

filter.type = 'button';
filter.appendChild(addText);
filter.addEventListener('click', listener, false);

element.appendChild(filter);
}

/* add - Contains the node to be added
* remove - Contains the node to be removed
*/
SortableTable.prototype.doOnClick = function(obj, add, remove) {
obj.removeChild(remove);
obj.appendChild(add);
};

If you needed to pass a lot of data, it might be more convenient to
place the "private" stuff in an object and pass that:

function SortableTable(id) {
var data = {
addText : document.createTextNode('Add'),
removeText : document.createTextNode('Remove')
};

function listener() {
me.doOnClick(this, data);
}
}

SortableTable.prototype.doOnClick = function(obj, data) {
obj.removeChild(data.addText);
obj.appendChild(data.removeText);
};

Hope that helps,
Mike

[1] <URL:http://jibbering.com/faq/>

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

This discussion thread is closed

Replies have been disabled for this discussion.