PDA

View Full Version : Why is only the last select element is being affected???



y1k2h3
11-17-2006, 04:09 AM
I have several <select> on my html page but the below function seems to work the only the LAST select element. The rest seems to have no effect at all. Isn't my code adding the new functions to every <select> within the loop.
My last try asking here :mad:


function normalizeDDWidth(){
var a = document.getElementsByTagName("select");
for(var i=0; i<a.length; i++){
var selectObj = a[i];
// alert(selectObj.id);

selectObj.onmouseover = function() { selectObj.style.width = 'auto'; }

selectObj.onblur = function(){
var selectedVal = selectObj.options[selectObj.selectedIndex].value;
if(selectedVal != ''){
selectObj.style.width = "auto";
}
else{
selectObj.style.width = "9em";
}
}


}//end for
}//end normalizeDDWidth()

Twey
11-17-2006, 03:26 PM
Read the Jibbering.com Closures FAQ (http://jibbering.com/faq/faq_notes/closures.html) for more information on your problem. The functions do get added to every <select>, but the selectObj modified within those functions is the one that exists after the loop has run all the way through. One way to cure this problem is to create a separate scope to hold the current element:
function normalizeDDWidth() {
for(var i = 0, a = document.getElementsByTagName("select"); i < a.length; ++i) {
a[i].onmouseover = (function() {
var selectObj = a[i];
return function() {
selectObj.style.width = "auto";
};
})();
a[i].onblur = (function() {
var selectObj = a[i];
return function() {
if(selectObj.options[selectObj.selectedIndex].value !== '')
selectObj.style.width = "auto";
else
selectObj.style.width = "9em";
};
})();
}
}... but a far better method (although one that may be unsuitable for your code, if it does things other than the snippet you've shown here) is to just use this to refer to the current element, and avoid creating all those unnecessary scopes:
function normalizeDDWidth() {
var overfunc = function() {
this.style.width = "auto";
};
var outfunc = function() {
if(this.options[this.selectedIndex].value !== '')
this.style.width = "auto";
else
this.style.width = "9em";
};
for(var i = 0, a = document.getElementsByTagName("select"); i < a.length; ++i) {
a[i].onmouseover = overfunc;
a[i].onblur = outfunc;
}
}

mwinter
11-17-2006, 11:26 PM
Read the Jibbering.com Closures FAQ (http://jibbering.com/faq/faq_notes/closures.html) for more information on your problem.

That's actually the FAQ notes for the comp.lang.javascript newsgroup. The notes provide more in-depth discussion than is suitable to be included in the FAQ itself.



The functions do get added to every <select>, but the selectObj modified within those functions is the one that exists after the loop has run all the way through.

That is to say that the function objects created within the for loop all share the local variables declared within the normalizeDDWidth function. When one of those variables is changed - in this case, the selectObj variable - all of the function objects created by the function expressions "see" that change.




function normalizeDDWidth() {
for(var i = 0, a = document.getElementsByTagName("select"); i < a.length; ++i) {
a[i].onmouseover = (function() {
var selectObj = a[i];
return function() {
selectObj.style.width = "auto";
};
})();
a[i].onblur = (function() {
var selectObj = a[i];
return function() {
if(selectObj.options[selectObj.selectedIndex].value !== '')
selectObj.style.width = "auto";
else
selectObj.style.width = "9em";
};
})();
}
}

Another reason to try and stay clear of that is that it will cause a memory leak in MSIE: [select element].onmouseover -> [function object].[[Scope]] -> [Variable object].selectObj -> [select element]. A similar circular reference exists with the blur event listener.

Mike