Michael said:
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.
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.
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