javascriptdocumentfragment

JavaScript: when string added to DocumentFragment.innerHTML, there are no children, how to fix?


When some html string added to DocumentFragment innerHTML property, there are no children exists. But same action with Element created by createElement show children. I created simple example for comparing innerHTML behavior for DocumentFragment and simple Element:

const fragment = document.createDocumentFragment();
const div = document.createElement('div')

fragment.innerHTML = "<i>Test</i>";
console.log('fragment children:', fragment.children); // empty
fragment.innerHTML = "<i><b>Test</b></i>";
console.log('fragment children:', fragment.children); // empty

div.innerHTML = "<i>Test</i>";
console.log('div children:', div.children) // has children
div.innerHTML = "<i><b>Test</b></i>";
console.log('div children:', div.children)  // has children

But fragment can show children added by appendChild:

const span = document.createElement('span');
const fragment2 = document.createDocumentFragment();
fragment2.appendChild(span);
console.log('fragment children for appendChild', fragment2.children);

How to fix this weird DocumentFragment behavior ?

ADDITIONAL: I need DocumentFragment as temporary HTML container.

JSFiddle with reproducing the problem.


Solution

  • div inherits from the HTMLElement prototype, a child of the Node prototype

    DocumentFragment inherits directly from the Node prototype.

    This is to say that div has all of the Node methods and properties as well as all HTMLElement methods and properties.

    DocumentFragment only has Node methods and properties.

    Though the Node prototype has the ability to have children, innerHTML does not exist as an innate property. This is only available on HTMLElement and its children (in this case HTMLDivElement ).

    Assigning to innerHTML on a child of a Node prototype simply creates the property innerHTML with your string as a value, but does nothing more.

    Basically, elements have internal wiring that tells them what to do when innerHTML is assigned/updated. Nodes do not.

    You can see this below:

    const fragment = document.createDocumentFragment();
    const div = document.createElement('div');
    
    console.log("innerHTML in fragment: " + ('innerHTML' in fragment) );
    console.log("innerHTML in element: " + ('innerHTML' in div) );


    In order to use something as a container and utilize innerHTML you would really just need to create an element that contains what you're trying to add. You can use a number of different things like a template Element or DOMParser, but honestly the easiest is just to create a separate div and classify it as a container

    let container = document.createElement("div");
    container.className = "container";
    
    let div = document.createElement("div");
    container.className = "child";
    
    container.appendChild(div);
    
    document.body.appendChild(container);
    .container {
    
    width: 100px;
    height: 100px;
    border: 1px solid red;
    }
    
    .child {
     width: 10px;
     height: 10px;
     border: 1px solid green;
    }