0

I'm trying to "keep" a subtree of the DOM for later use and reappending based on some user action (a subtree which I initially created and manipulated using a DocumentFragment and then appended to the DOM), but I don't want to append and hide it somewhere in the DOM, because further (and heavy in my case) manipulation on it is slower and incurs layout reflows and further performance impact.

Is there a cross-browser way (IE11+ for what I care) to convert some DOM subtree back into a DocumentFragment? Didnt' find anything yet by searching SO or the docs.

Thank you

user777
  • 906
  • 5
  • 16
  • i don't know if this help you : [Create reusable document fragment from the DOM](http://stackoverflow.com/questions/14048432/create-reusable-document-fragment-from-the-dom) – j.kherfan Mar 28 '17 at 14:00
  • @j.kherfan Thanks but I don't see them converting anything back into a DocumentFragment – user777 Mar 28 '17 at 14:05

1 Answers1

0

I'd suggest to keep the nodes you're interested in in an Array. It's more handy that a DocumentFragment, and not as nasty as a NodeList or HTMLCollection.

A little utility to convert "things" into documentFragments.

function fragmentFlush(state){
    if(state.text){
        state.fragment.appendChild(document.createTextNode(state.text));
        state.text = "";
    }
    return state.fragment;
}

function fragmentIterate(state, value){
    if( value instanceof Node ){
        fragmentFlush(state).appendChild(value);
    }else if(Array.isArray(value)){
        value.reduce(fragmentIterate, state);
    }else if(value === Object(value)){
        fragmentIterate(state, Array.from(value));
    }else if(value != null){
        state.text += value;
    }
    return state;
}

function fragment(value){
    return fragmentFlush(fragmentIterate({
        text: "",
        fragment: document.createDocumentFragment()
    }, value));
}

"things" because It traverses any (non-cyclic) arraylike structure to find the nodes you've passed and builds a (flattened) documentFragment from that. (Primitive values are converted to TextNodes, null and undefined are ignored)

var setA = [/*...*/];

var frag = fragment([
    "setA: ", setA,
    condition? "some more text": null,  //null values are ignred
    "setB: ", someNode.children,
    //that's why I made this traverse recursively
    //so that I can "concat" lists like the following line
    //without having to actually concat them
    "setC: ", [setA, anotherSet, /* moreNodes */, andAnotherSet]
]);

node.appendChild(frag);

Again beware, doesn't deal with cyclic references!

About the three functions, I've just extracted this from one of my libs. You'd probably want to put that into a module and only export fragment or wrap it into an IIFE.

Thomas
  • 11,958
  • 1
  • 14
  • 23