JavaScript - Concatenating NodeLists
In JavaScript, you cannot concatenate two nodeLists using Array.concat(). This is because nodeLists are not true Arrays, they are more like Objects that happen to have a length property. Here's an example scenario:
As a workaround, I wrote a quick method that will join two nodelists:
Note that I use list1[list1.length] = list2[i] instead of list1.push(list2[i]). This is for compatibility with IE 5.
To Do: Make a function that accepts an unlimited number of nodeLists and joins them all.
var pElements = document.body.getElementsByTagName("p");
var divElements = document.body.getElementsByTagName("div");
// This results in a new array where the last element is the entire
divElements nodeList
var pAndDivElements = pElements.concat(divElements);
As a workaround, I wrote a quick method that will join two nodelists:
joinNodeLists: function(list1,list2){
var i = list2.length - 1;do{ list1[list1.length] = list2[i];
}
while(i--);return list1;
}
Note that I use list1[list1.length] = list2[i] instead of list1.push(list2[i]). This is for compatibility with IE 5.
To Do: Make a function that accepts an unlimited number of nodeLists and joins them all.
8 Comments:
Thanks for the function ... exactly what I needed.
Hmmm, Thanks very much; works just like it says on the tin. However why cant I inline the code?
i=doc.getElementsByTagName("input");
t=doc.getElementsByTagName("textarea");
var ie=i.length -1;
do { t[t.length]=i[ie]; } while (ie--);
alert(t.length);
I only need the routine once and it seemed simple enough to inline. But it does not work. Why not?
Rgds Fergus
Um, have you checked to make sure this actually works? NodeLists are readonly, so what I found when I ran your function was that the length of the nodelist wouldn't update on subsequent loop iterations, meaning new items clobbered previous ones. I solved this by declaring an array and pushing the items onto that. Unlike the nodelist, the array length will update as you add new elements. I also wrote a version that accepts an indefinite number of nodelist arguments:
function joinNodeLists() {
if (!arguments.length) {
return;
}
var newList = [];
for (var i = 0; i < arguments.length; i++) {
var list = arguments[i];
for (var j = 0; j < list.length; j++) {
// Don't use push() for IE 5 compatibility
// newList.push(list[j]);
newList[newList.length] = list[j];
}
}
return newList;
}
Interesting - what browser(s) are you testing in? (To answer your first question: yes, I do test my code :P ) I wonder if what you're seeing has anything to do with the problems anonymous had when he tried to take the code out of the context of a function.
I only tested this in Firefox and found it didn't work. Using Firebug's debugger I could see the failure of the nodelist's length property to update as items were concatenated.
I retract my remarks. It turns out the error was my code that called joinNodeLists. Sorry about that. So to handle an indefinite number of nodeList arguments, you can just have:
function joinNodeLists(){
if (!arguments.length) {
return null;
}
var newList = arguments[0];
for (var i = 1; i < arguments.length; i++) {
var list = arguments[i];
for (var j = 0; j < list.length; j++) {
// Don't use push() for IE 5 // compatibility
newList.push(list[j]);
newList[newList.length] = list[j];
}
}
return newList;
}
Hi Rebecca,
Glad you got it sorted out. Looking at your code, it seems there's a comment missing:
// Don't use push() for IE 5 // compatibility
newList.push(list[j]);
newList[newList.length] = list[j];
Shouldn't the newList.push(list[j]) line be commented out?
It didn't work in firefox. This does:
function joinNodeLists(){
if (!arguments.length) {
return null;
}
var newList = new Array();
for (var i = 0; i < arguments.length; i++) {
var list = arguments[i];
for (var j = 0; j < list.length; j++) {
// Don't use push() for IE 5 // compatibility
newList[newList.length] = list[j];
}
}
return newList;
}
Post a Comment
<< Home