How to correctly use innerHTML to create an element (with possible children) from a html string?


Note: I do NOT want to use any framework.


The goal is just to create a function that will return an element based on an HTML string.


Assume a simple HTML Document like such:

<html>
<head></head>
<body>
</body>
</html>

All functions mentioned are in included the head section and all DOM creation/manipulation is done at the end of the body in a script tag.


I have a function createElement that takes a well formed HTML String as an argument. It goes like this:

function createElement(str)
{
  var div = document.createElement('div');
  div.innerHTML = str;
  return div.childNodes;
}

Now this functions works great when you call it like such:

var e = createElement('<p id="myId" class="myClass">myInnerHTML</p>');

With the minor (possibly HUGE) problem that the element created isn't a 'true' element, it still has a parentNode of 'div'. If anyone knows how to fix that, then that would be awesome.


Now if I call the same function with a more complex string:

var e = createElement('<p id="myId" class="myClass">innerHTML<h2 id="h2ID" class="h2CLASS">Heading2</h2></p>');

It creates TWO children instead of ONE child with another child having another child.

Once you do div.innerHTML = str. The innerHTML instead of

`<p id="myId" class="myClass">innerHTML    <h2 id="h2ID" class="h2CLASS">Heading2</h2>    </p>`

turns to

`<p id="myId" class="myClass">innerHTML</p>        <h2 id="h2ID" class="h2CLASS">Heading2</h2>`


Questions:

  1. Can I somehow get an element without a parent node after using .innerHTML?
  2. Can I (in the case of the slightly complex string) get my function to return ONE element with the appropriate child instead of two elements. [It actually returns three, <p.myClass#myId>,<h2.h2CLASS#h2ID>, and another <p>]

This is similar to the answer from palswim, except that it doesn't bother with creating a clone, and uses a while() loop instead, always appending the node at [0].

function createElement( str ) {
    var frag = document.createDocumentFragment();

    var elem = document.createElement('div');
    elem.innerHTML = str;

    while (elem.childNodes[0]) {
        frag.appendChild(elem.childNodes[0]);
    }
    return frag;
}

You'd have to attach the new element somewhere. Try using a DocumentFragment object in conjunction with the div you created:

function createElement(str) {
    var div = document.createElement('div');
    div.innerHTML = str;
    var container = document.createDocumentFragment();
    for (var i=0; i < div.childNodes.length; i++) {
        var node = div.childNodes[i].cloneNode(true);
        container.appendChild(node);
    }
    return container.childNodes;
}

It's more overhead, but it does what you want. Note that DOM elements' .insertAdjacentHTML member function is coming in HTML5.

For that complex string you passed, it isn't valid XHTML syntax - you can't have a block element as a child of <p> (<h2> is a block level element).