javascriptnodesnodelist

Create node list from a single node in JavaScript


This is one of those it seems so simple, but I cannot come up with a good way to go about it.

I have a node, maybe nodelist = document.getElementById("mydiv"); - I need to normalize this to a node list. And not an array either: an actual, bona-fide nodeList object.

Not nodelist = [document.getElementById("mydiv")];

No libraries, please.


Solution

  • Reviving this because I recently remembered something about JavaScript. This depends on how the NodeList is being checked, but..

    const singleNode = ((nodeList) => (node) => {
      const layer = { // define our specific case
        0: { value: node, enumerable: true },
        length: { value: 1 },
        item: {
          value(i) {
            return this[+i || 0];
          }, 
          enumerable: true,
        },
      };
      return Object.create(nodeList, layer); // put our case on top of true NodeList
    })(document.createDocumentFragment().childNodes); // scope a true NodeList
    

    Now, if you do

    const list = singleNode(document.body); // for example
    
    list instanceof NodeList; // true
    list.constructor === NodeList; // true
    

    and list has properties length 1 and 0 as your node, as well as anything inherited from NodeList.

    If you can't use Object.create, you could do the same except as a constructor with prototype nodelist and set this['0'] = node;, this['length'] = 1; and create with new.


    ES5 version

    var singleNode = (function () {
        // make an empty node list to inherit from
        var nodelist = document.createDocumentFragment().childNodes;
        // return a function to create object formed as desired
        return function (node) {
            return Object.create(nodelist, {
                '0': {value: node, enumerable: true},
                'length': {value: 1},
                'item': {
                    "value": function (i) {
                        return this[+i || 0];
                    }, 
                    enumerable: true
                }
            }); // return an object pretending to be a NodeList
        };
    }());