Concatenating html object arrays with javascript
Asked Answered
K

4

13

I'm attempting to merge two arrays made up of html objects. For some reason using .concat() will not work for me.

Here's a simple pen to demonstrate the problem: http://codepen.io/anon/pen/kIeyB

Note: I tried searching for something remotely similar but found nothing that answered my question.

I figure you can do this the ole fashion way using for-loops but I rather not re-invent the wheel.

var x = document.getElementById("hello");
var items = x.getElementsByClassName("one");
//alert(items.length);
var items2 = x.getElementsByClassName("two");
//alert(items2.length);
items = items.concat(items2);
//alert(items.length);
Kanishakanji answered 10/6, 2014 at 5:5 Comment(2)
Please state the actual problem and include a valid example to reproduce the problem.Claudine
The codepen clearly illustrates the issue I was having as the 6th line would results in an execution error.Kanishakanji
M
13

items and items2 are nodeList or HTMLCollection objects, not arrays. They do not contain a .concat() method. They have a .length property and support [x] indexing, but they do not have the other array methods.

A common workaround to copy them into an actual array is as follows:

// convert both to arrays so they have the full complement of Array methods
var array1 = Array.prototype.slice.call(x.getElementsByClassName("one"), 0);
var array2 = Array.prototype.slice.call(x.getElementsByClassName("two"), 0);
Mason answered 10/6, 2014 at 5:20 Comment(3)
Thank you, this works perfectly! Out of curiosity, could you explain the slice.call() and what the '0' parameter is for.Kanishakanji
@user3718546: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….Sliwa
@Kanishakanji - .slice() works with anything that has a .length and supports [i] indexing from 0 to length - 1 (which includes a nodeList, and HTMLCollection, and arguments` object, etc...). So, we're using the .slice() method from Array.prototype and calling that method, but passing it a nodeList as the object to operate on with .call(). The 0 is the first argument to .slice() which means to start the shallow copy at the beginning. If you read the doc for both .slice() and .call(), you will see how they work together.Mason
L
7

This can be also be done like this:

var allitems = [];
allitems = Array.prototype.concat.apply(allitems, x.getElementsByClassName("one"));
allitems = Array.prototype.concat.apply(allitems, x.getElementsByClassName("two"));

The allitems variable will be a single javascript Array containing all elements with class one & two.

Leak answered 13/1, 2017 at 0:29 Comment(1)
siplest solution!Pages
H
1

document.getElementsByClassName doesn't return an array. It returns NodeList which has length property.

Hofstetter answered 10/6, 2014 at 5:10 Comment(0)
S
0

What you have are HTMLCollections, which although behave like arrays, but are not arrays. See here: https://developer.mozilla.org/en/docs/Web/API/HTMLCollection:

..A collection is an object that represents a lists of DOM nodes..

In your case, you could concatenate these objects together into a new array:

var itemsnew;
var x = document.getElementById("hello");
var items = x.getElementsByClassName("one");
var items2 = x.getElementsByClassName("two");
itemsnew = Array.prototype.concat.call(items, items2);

Now, if you:

console.log(itemsnew);

Will return:

[HTMLCollection[1], HTMLCollection[1]]

And:

console.log(itemsnew[0][0]);

Will return:

<div class="one"></div>
Sliwa answered 10/6, 2014 at 5:26 Comment(1)
Thank you for your answering and everything you said was correct. For my situation; however, I was trying to concatenate multiple arrays so that I could then transverse them in one loop. Having a multi-dimensional array like you proposed wouldn't be the most appropriate and most useful approach for users trying to manipulate multiple nodeLists.Kanishakanji

© 2022 - 2024 — McMap. All rights reserved.