views:

2062

answers:

6

Hello All,

is there a way to join 2 NodeLists returned by 2 calls of document.getElementsByTagName?

Say, I have the following code

var inputs = documentElement.getElementsByTagName('input');
var selects = document.getElementsByTagName('select');

I want to loop through the results. Is it possible in one loop?

Thank you in advance!

A: 

Why don't you try jQuery.

jQuery Traverse API reference

Download jQuery -> http: //linux.softpedia.com/downloadTag/traverse+HTML+documents

Green Techy
A: 

As far as I know, the NodeList type is immutable (see this article for example), which means you'll have to generate your own object.

A simple method would just be to create an array and copy all the elements into that array.

var inputs = documentElement.getElementsByTagName('input');
var selects = document.getElementsByTagName('select');
var all = new Array(inputs.length + selects.length);

var index = 0;
for (i = 0; i < inputs.length; i++)
    all[index++] = inputs[i];
for (i = 0; i < selects.length; i++)
    all[index++] = selects[i];

The all variable then contains the union of the two sets of nodes.

Noldorin
It will need 2 loops anyway. For my particular task I need to loop through the results only once so creating an object is not worth it. I can't join the results and that's what I wanted to know, thank you!
dasha salo
Yeah, using two loops is the clearest solution in my opinion, anyway. (I considered the one loop option, but it doesn't really help things.) Glad you have a solution.
Noldorin
A: 

First, I thought that this is possible to concat arrays using Array.prototype, like this:

Array.prototype.concat.call(selects, inputs);

But it doesn't work, so that I've made an arrays from node collections and concat it. Looks like that:

(function () {

    var inputs = document.getElementsByTagName('input'),
        selects = document.getElementsByTagName('select'),
        result,
        i,
        node;

    function convert (collection) {
        var a = [];
        for (var i = 0, length = collection.length; i < length; i++) {
            a.push(collection[i]);
        }
        return a;
    }

    // concatenation && convertation
    result = Array.prototype.concat(convert(inputs), convert(selects));
    // traversing
    i = result.length;
    while(node = result[--i]) {
        alert(node.getAttribute('name'));
    }

})();
Alexander Ulizko
I believe the first trick works in any (major) browser except for IE.
Ionuț G. Stan
And first trick won't work at WebKit-based browsers (safari, chrome)
Alexander Ulizko
+2  A: 

You can't join them, but you can still loop through them sequentially in one loop like this:

for ( var i = 0; i < inputs.length + selects.length; i++ ) {
    var element = ( i < inputs.length ) ? inputs[i] : selects[i-inputs.length];
}

Alternatively, using jQuery, you could select them all in one go:

$('input, select')
Mario Menger
+1 for providing both options, and the elegant for loop
annakata
+1 for pointing out the jQuery option.
Neil Barnwell
Nice! thnaks :)
dasha salo
+4  A: 

Seems like you can use the same Array.prototype.slice.call that makes the args array-like object become an array. (See here)

var inputs = document.getElementsByTagName('input');
var selects = document.getElementsByTagName('select');

inputs = Array.prototype.slice.call(inputs);
selects = Array.prototype.slice.call(selects);

var res = inputs.concat(selects);

alert(res.length);
Simon
I was just about to say that :) +1 Prototype and other libraries use slice to convert the node lists to arrays.
Jonathan Fingland
A minor thing to keep in mind is that this won't work in Internet Explorer or the BlackBerry browser. jQuery 1.4 has an interesting test that is used to fall back to a loop to combine Node Lists. I've excerpted it here: http://pastebin.com/TkTwMG17
Dan Herbert
A: 
document.querySelectorAll("input, select"); 
Yansky