I am attempting to merge two arrays of objects to so I can validate a form. The usual concat method does not appear to work in this circumstance. Concat works with ordinary numerical and string arrays but doesn't with object arrays. The line var allTags = allInputs.concat(allSelects);
does not work.
var allInputs = document.getElementsByTagName("input");
alert("Inputs: " + allInputs.length);
var allSelects = document.getElementsByTagName("select");
alert("Selects: " + allSelects.length);
var allTags = allInputs.concat(allSelects);
alert("allTags: " + allTags.length);
A NodeList may look like an array, but in reality, they both are two completely different things. A NodeList object is basically a collection of DOM nodes extracted from the HTML document. An array is a special data-type in JavaScript, that can store a collection of arbitrary elements.
To merge elements from one array to another, we must first iterate(loop) through all the array elements. In the loop, we will retrieve each element from an array and insert(using the array push() method) to another array. Now, we can call the merge() function and pass two arrays as the arguments for merging.
To merge objects by id with JavaScript, we use the map method and the spread operator. const a1 = [ { id: 1, name: "test" }, { id: 2, name: "test2" }, ]; const a2 = [ { id: 1, count: "1" }, { id: 2, count: "2" }, ]; const a3 = a1.
Concat works with ordinary numerical and string arrays but doesn't with object arrays.
Actually, it does, but NodeList
instances don't have a concat
method, and Array#concat
doesn't have a means of identifying that you want to flatten those (because they're not arrays).
But it's still fairly easy to do (see caveat below, though). Change this line:
var allTags = allInputs.concat(allSelects);
to
var allTags = [];
allTags.push.apply(allTags, allInputs);
allTags.push.apply(allTags, allSelects);
Live Example | Source
That works by using a bit of a trick: Array#push
accepts a variable number of elements to add to the array, and Function#apply
calls the function using the given value for this
(in our case, allTags
) and any array-like object as the arguments to pass to it. Since NodeList
instances are array-like, push
happily pushes all of the elements of the list onto the array.
This behavior of Function#apply
(not requiring the second argument to really be an array) is very clearly defined in the specification, and is well-supported in modern browsers.
Sadly, IE6 and 7 don't support the above (I think it's specifically using host objects — NodeLists
— for Function#apply
's second argument), but then, we shouldn't be supporting them, either. :-) IE8 doesn't, either, which is more problematic. IE9 is happy with it.
If you need to support IE8 and earlier, sadly, I think you're stuck with a boring old loop:
var allInputs = document.getElementsByTagName('input');
var allSelects = document.getElementsByTagName('select');
var allTags = [];
appendAll(allTags, allInputs);
appendAll(allTags, allSelects);
function appendAll(dest, src) {
var n;
for (n = 0; n < src.length; ++n) {
dest.push(src[n]);
}
return dest;
}
Live Example | Source
That does work on IE8 and earlier (and others).
document.get[something]
returns a NodeList, which looks very similar to an Array, but has numerous distinctive features, two of which are:
If you don't have any issues with turning your NodeLists into actual arrays, you could do the following to achieve the effect you desire:
var allInputs = document.getElementsByTagName("input")
, allSelects = document.getElementsByTagName("select")
;//nodeLists
var inputList = makeArray(allInputs)
, selectList = makeArray(allSelects)
;//nodeArrays
var combined = inputList.concat(selectList);
function makeArray(list){
return Array.prototype.slice.call(list);
}
You will lose any and all behaviors of the original NodeList, including it's ability to update in real time to reflect changes to the DOM, but my guess is, that's not really an issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With