Best practice for converting a nodelist to an array

Even with the penetration of ES6 runtimes, converting js.html.NodeList to Array without using Array.from() is still something one needs to do. (IE11 is still very much at large, and Haxe’s Array doesn’t offer a from() method).

I was kinda hoping that Haxe’s js library would offer a cast for this, but I can’t imagine how, since a nodelist is not any kind of array. It’s just a collection with a length property.

I searched here and on the old google group for the preferred Haxe way to do this, but could find nothing.

Of course, I can make a loop, and copy the nodes over (casting each as Element as I push them in) but since vanilla js offers several one-line solutions to this fairly common problem, I hope I can be forgiven for expecting some Haxe sugar here.

This is not something which needs to be super-performant. I only do it at initialisation time. Main criteria for this solution are clarity, followed by brevity. Any suggestions?

Thank you!

1 Like

Perhaps you could use array comprehension to make it a bit more concise?

Perfect!

[for (node in nodelist) cast(node, Element)]

does the right thing in one line. Thank you.

1 Like

You can also make a utility class with static extension like below, add import NodeListUtil to your import.hx (global imports) and then you can do nodelist.toArray(); from anywhere in your code :fire:

class NodeListUtil {
  public inline static function toArray(nodelist:js.html.NodeList):Array<js.html.Element> {
    return [for (node in nodelist) cast(node, Element)];
  }
}
2 Likes

The common JS way for this (before Array.from) was using Array.prototype.slice.call, which might be a bit faster than looping through the list (haven’t tested), so my function is:

inline public static function toArray<E:DOMElement>(nodes:ListOrCollection):Array<E>
  return untyped Array.prototype.slice.call(nodes);

typedef ListOrCollection = haxe.extern.EitherType<js.html.NodeList,js.html.HTMLCollection>;

There are some JS functions returning a HTMLCollection, which need the same conversion, so I added that to a typedef. Also I return a generic array, that I can be typed to Array<InputElement> e.g. and I use DOMElement as parameter because it covers SVG elements as well.

2 Likes