8

Is there a way to convert markup string to node object in JavaScript? Actually I am looking for the subsitute for:

document.getElementById("divOne").innerHTML += "<table><tbody><tr><td><input type='text' value='0' /></td></tr></tbody></table>"

something like

document.getElementById("divOne").appendChild(document.createNodeFromString("<table><tbody><tr><td><input type='text' value='0' /></td></tr></tbody></table>"))

using createNodeFromString rather creating the table element then append its child elements then attach their respective attributes and values!

vulcan raven
  • 32,612
  • 11
  • 57
  • 93
  • 1
    I am curious why setting innerHTML does not work for you. After you set innerHTML you can get the resulting element by querying your divOne. – akonsu Feb 17 '12 at 20:08
  • @akonsu, supposedly you have in divOne and outside this div you have a button with onclick= innerHTML-method. Now, in FF10 and IE9 (with document mode IE9) enter something in the textbox and press the button, the value of input would be reset! I am trying to see would same thing happen with appendChild. Btw, in IE8 compatibility mode, the value of input element is persistent.. – vulcan raven Feb 17 '12 at 20:17
  • are you saying that if you have a text input field and a button, the value of the input field gets cleared when you press the button? could you demonstrate this on, say, jsbin.com? – akonsu Feb 17 '12 at 20:26
  • Have you considered using a framework such as jQuery? Makes that kind of task much easier... – ThiefMaster Feb 17 '12 at 20:29
  • Try it in FF10 or IE9 with native compatibility and then in IE8 compatibility mode: http://jsbin.com/amodag Also, `document.getElementById("divOne").appendChild(document.createElement("input")) ` does retain the value of input in IE9 but I need to append the entire table in a single statement. – vulcan raven Feb 17 '12 at 20:31
  • No need for a library like jQuery. This kind of task is plenty easy without. –  Feb 17 '12 at 20:34
  • That behaviour is because `innerHTML += 'foo'` is first getting `innerHTML` and then setting it to that value + `'foo'`. Because `innerHTML` does not contain the current value (as well as event handlers and everything else not visible in the HTML), all corresponding elements are reconstructed the same way as the first time they were parsed (so, using the default value). – pimvdb Feb 17 '12 at 20:36
  • @akonsu Many (interactive) elements have an attribute and a property. The attribute is the default value, and specified in the HTML. The property is dynamic, and reflects the actual state. When `.innerHTML` is used, only the attributes are returned, *not* the properties. That's the cause of the cleared `` fields: The `value` attribute is possibly an empty string, and the `value` **property** is not obtained through `.innerHTML`. – Rob W Feb 17 '12 at 20:37

4 Answers4

17

There's not an existing cross-browser function for this. The following method can be used to achieve the desired effect (using a DocumentFragment for an optimized performance, based on this answer):

function appendStringAsNodes(element, html) {
    var frag = document.createDocumentFragment(),
        tmp = document.createElement('body'), child;
    tmp.innerHTML = html;
    // Append elements in a loop to a DocumentFragment, so that the browser does
    // not re-render the document for each node
    while (child = tmp.firstChild) {
        frag.appendChild(child);
    }
    element.appendChild(frag); // Now, append all elements at once
    frag = tmp = null;
}

Usage (indention for readability):

appendStringAsNodes(
    document.getElementById("divOne"),
   "<table><tbody><tr><td><input type='text' value='0' /></td></tr></tbody></table>"
);
Community
  • 1
  • 1
Rob W
  • 341,306
  • 83
  • 791
  • 678
4

Yes, you can do that.

var myNewTable = document.createElement("table");
myNewTable.innerHTML = "<tbody><tr><td><input type='text' value='0' /></td></tr></tbody>"
document.getElementById("divOne").appendChild(myNewTable);
caleb
  • 1,579
  • 12
  • 12
  • Older IE versions will complain about this, because they cannot handle setting the `innerHTML` property on some elements, including ``. See also [this article](http://support.microsoft.com/kb/239832).
    – Rob W Feb 17 '12 at 20:31
1

some news on this topic:

the modern approach is to use the <template> tag, which you place e.g. before the body closes (the browser will ignore it).

it's a standardization of client side templating, and doesn't need to use .innerHTML, which could lead to security issues (XSS)

example:

<template id='tplArticle'>
  <article class='newsItem'>
    <h1 class='title'></h1>
    <p class='paragraph'>
  </article>
</template>

whenever you need it, you just grab its content and clone (!!) it to reuse it:

// .content will grab the content of the template, not the <template> tag
// this will return a document fragment
const $articleFragment = document.querySelector('#tplArticle').content;

// clone it, otherwise you get the same reference and it won't be reusable (true makes a deep copy)
const $article = document.importNode($articleFragment, true);

// then e.g. append it to the body
document.body.appendChild($article);
faebster
  • 727
  • 7
  • 13
  • Nice and efficient, thanks! https://caniuse.com/?search=%3Ctemplate%3E suggests that we should just use it in this day and age. – vulcan raven Dec 06 '21 at 13:08
  • also nice to check out: WebComponents: https://developer.mozilla.org/en-US/docs/Web/Web_Components ( – faebster Dec 06 '21 at 13:13
0
function htmlMarkupToNode(html){
    let template = document.createElement("template");        
    template.innerHTML = html ;
    let node = template.content.cloneNode(true) ;        
    return node ;   
}

document.getElementById("divOne").appendChild(htmlMarkupToNode("<table><tbody><tr><td><input type='text' value='0' /></td></tr></tbody></table>"));
Bob
  • 1,589
  • 17
  • 25
  • ah, just seen your post now, sorry for adding it myself, I've tried to be a bit more detailed though... btw you can add the language of the code (to format it) by adding the language name after the 3 backticks – faebster Dec 05 '21 at 14:19