I am running some tests. I want to pass maybe an HTMLCollection or a single element wrapped in an array [element] or [elements]
and end up with an iterable array [el] or [el1, el2, el3 etc..]
— something I will be passing to various dom methods.
Example HTML
<div>
<ul id='list'>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
I had hoped that I could do something like [].flat.call(domElements)
So a test on the following
const elements = [
document.getElementsByTagName('li'),
document.getElementById('list'),
['a', 'b', 'b'],
'def'
]
Array flat output
console.log(elements.flat())
// Array flat (6) [ HTMLCollection(6), ul#list, "a", "b", "b", "def" ]
The HTMLCollection is left untouched, which isn’t what I want.
I ended up writing the following
// returns a flattened array, including flattening nodelists, strings etc.
const flattenEverything = arr => {
const isIterable = obj => typeof obj[Symbol.iterator] === 'function'
return arr.reduce(
(acc, val) =>
acc.concat((isIterable(val)) ? Array.from(val) : [val])
, []
)
}
flattenEverything output
flattenEverything(elements)
// (13) [li, li, li, li, li, li, ul#list, "a", "b", "b", "d", "e", "f"]
I know I could just go down the if/else route, but I am kind of looking for a nice one shop route to this.
Would be interested in thoughts. codepen here
Thanks