Append HTML to container element without innerHTML
Asked Answered
T

6

250

I need a way to append HTML to a container element without using innerHTML. The reason why I do not want to use innerHTML is because when it is use like this:

element.innerHTML += htmldata

It works by replacing all of the html first before adding the old html plus the new html. This is not good because it resets dynamic media such as embedded flash videos...

I could do it this way which works:

var e = document.createElement('span');
e.innerHTML = htmldata;
element.appendChild(e);

However the problem with that way is that there is that extra span tag in the document now which I do not want.

How can this be done then? Thanks!

Tropous answered 10/6, 2011 at 9:27 Comment(1)
Why not use Jquery? Check my detailed answer below. https://mcmap.net/q/115806/-append-html-to-container-element-without-innerhtmlTungstite
T
115

To give an alternative (as using DocumentFragment does not seem to work): You can simulate it by iterating over the children of the newly generated node and only append those.

var e = document.createElement('div');
e.innerHTML = htmldata;

while(e.firstChild) {
    element.appendChild(e.firstChild);
}
Thermel answered 10/6, 2011 at 10:10 Comment(4)
I thought we're looking for a solution that does not use "innerHTML"Knackwurst
@kennydelacruz: The OP didn't want to append new HTML to an existing HTML because it destroys and recreates the existing elements. The OP found a solution by creating a new element and append that but they didn't want to add an additional element. I just extended that solution to show that they can move/append the newly created elements, which don't impact the existing elements.Thermel
I know this is old, but can anyone explain to me why one can iterate over e.firstChild?Suber
@Toastgeraet: This is example is not iterating over e.firstChild. Rather, it checks whether e has a child and if yes, move that child over to the element.Thermel
F
789

Check out the insertAdjacentHTML() method. The first parameter is where you want the string appended and takes ("beforebegin", "afterbegin", "beforeend", "afterend"). In the OP's situation you would use "beforeend". The second parameter is just the html string.

Basic usage:

var d1 = document.getElementById('one');
d1.insertAdjacentHTML('beforeend', '<div id="two">two</div>');
Fibril answered 24/3, 2012 at 11:51 Comment(12)
Just tried your solution as well as the accepted. Both works, but yours is only 2 lines and no loops. Sounds like a winner to me.Pontias
For reference to anyone who might choose this route: This method doesn't play nice with tables in IE9.Pontias
In Chrome it tells me Uncaught TypeError: undefined is not a function !Bowel
This hidden gem needs more exposure.Calendre
You'll get an error if you try to use this method on something that isn't a Node, just FYI.Crystallite
I use this coding to validate that the text is surrounded by an HTML tag if (/^<([a-z]+)[^>]*>[\S\s]*<\/\1>$/i.test(output) === false) {output = '<div>' + output + '</div>';}Edmee
I got Uncaught TypeError: XXX is not a function Turns out I was trying to manipulate a HTMLCollection, so I had to index it to get an element first. e.g. var element = document.getElementsByClassName('className'); element[0].insertAdjacentHTML('beforeend', '<div> ... </div>');Melpomene
Tested in FF and Chrome and works smoothly. Thanks!!Longs
My go-to if supporting legacy browsers isn't a thing!Graham
pretty annoying that this method doesn't autocomplete in the Chrome web-console. v79Suffer
I didn't know about the innerAdjascentHTML method. Upvoted for sure!Greatuncle
I found this thread on Google because I remembered the method existed but didn't remember the name. Thanks!Ketch
T
115

To give an alternative (as using DocumentFragment does not seem to work): You can simulate it by iterating over the children of the newly generated node and only append those.

var e = document.createElement('div');
e.innerHTML = htmldata;

while(e.firstChild) {
    element.appendChild(e.firstChild);
}
Thermel answered 10/6, 2011 at 10:10 Comment(4)
I thought we're looking for a solution that does not use "innerHTML"Knackwurst
@kennydelacruz: The OP didn't want to append new HTML to an existing HTML because it destroys and recreates the existing elements. The OP found a solution by creating a new element and append that but they didn't want to add an additional element. I just extended that solution to show that they can move/append the newly created elements, which don't impact the existing elements.Thermel
I know this is old, but can anyone explain to me why one can iterate over e.firstChild?Suber
@Toastgeraet: This is example is not iterating over e.firstChild. Rather, it checks whether e has a child and if yes, move that child over to the element.Thermel
A
18

alnafie has a great answer for this question. I wanted to give an example of his code for reference:

var childNumber = 3;

function addChild() {
  var parent = document.getElementById('i-want-more-children');
  var newChild = '<p>Child ' + childNumber + '</p>';
  parent.insertAdjacentHTML('beforeend', newChild);
  childNumber++;
}
body {
  text-align: center;
}
button {
  background: rgba(7, 99, 53, .1);
  border: 3px solid rgba(7, 99, 53, 1);
  border-radius: 5px;
  color: rgba(7, 99, 53, 1);
  cursor: pointer;
  line-height: 40px;
  font-size: 30px;
  outline: none;
  padding: 0 20px;
  transition: all .3s;
}
button:hover {
  background: rgba(7, 99, 53, 1);
  color: rgba(255,255,255,1);
}
p {
  font-size: 20px;
  font-weight: bold;
}
<button type="button" onclick="addChild()">Append Child</button>
<div id="i-want-more-children">
  <p>Child 1</p>
  <p>Child 2</p>
</div>

Hopefully this is helpful to others.

Accomplice answered 2/2, 2017 at 19:52 Comment(1)
I hate to be a stickler for the rules but I think it would have been better if you created a demo (jsfiddle, codepen, etc) and then added that to Alnafie's answer by using the edit feature or submitting a comment. Creating an answer only to demonstrate another user's answer is not how SO works, regardless of how useful the information you provided is. Imagine if every user decided to demonstrate another answer by creating an answer - it would get messy.Envisage
R
5

This is what DocumentFragment was meant for.

var frag = document.createDocumentFragment();
var span = document.createElement("span");
span.innerHTML = htmldata;
for (var i = 0, ii = span.childNodes.length; i < ii; i++) {
    frag.appendChild(span.childNodes[i]);
}
element.appendChild(frag);

document.createDocumentFragment, .childNodes

Ravage answered 10/6, 2011 at 9:32 Comment(8)
I just tested this and it does not work. Is that how it should be used?Tropous
Where are you getting (a) from? Is that a typo.Blackmarketeer
Yes that is a typo, it should be e. I do not think you can use innerHTML for a fragment. This is not workingTropous
@Tropous I've gone for the cop-out use jQuery.Ravage
jQuery no no! I am not going to include jQuery just for one small function :\ It is just overkillTropous
@Tropous you want to convert HTML to DOM. So either RIP out that conversion logic yourself. Or add a span with the innerHTML wrapped in it then remove that span from the DOM.Ravage
How would I remove the span without removing its child nodes after I append it?Tropous
@Tropous updated the question. It's so easy, should have thought of that before.Ravage
T
3
<div id="Result">
</div>

<script>
for(var i=0; i<=10; i++){
var data = "<b>vijay</b>";
 document.getElementById('Result').innerHTML += data;
}
</script>

assign the data for div with "+=" symbol you can append data including previous html data

Taciturnity answered 9/6, 2015 at 8:6 Comment(1)
The question specifically requires not using element.innerHTML += data.Vouchsafe
C
-1

How to fish and while using strict code. There are two prerequisite functions needed at the bottom of this post.

xml_add('before', id_('element_after'), '<span xmlns="http://www.w3.org/1999/xhtml">Some text.</span>');

xml_add('after', id_('element_before'), '<input type="text" xmlns="http://www.w3.org/1999/xhtml" />');

xml_add('inside', id_('element_parent'), '<input type="text" xmlns="http://www.w3.org/1999/xhtml" />');

Add multiple elements (namespace only needs to be on the parent element):

xml_add('inside', id_('element_parent'), '<div xmlns="http://www.w3.org/1999/xhtml"><input type="text" /><input type="button" /></div>');

Dynamic reusable code:

function id_(id) {return (document.getElementById(id)) ? document.getElementById(id) : false;}

function xml_add(pos, e, xml)
{
 e = (typeof e == 'string' && id_(e)) ? id_(e) : e;

 if (e.nodeName)
 {
  if (pos=='after') {e.parentNode.insertBefore(document.importNode(new DOMParser().parseFromString(xml,'application/xml').childNodes[0],true),e.nextSibling);}
  else if (pos=='before') {e.parentNode.insertBefore(document.importNode(new DOMParser().parseFromString(xml,'application/xml').childNodes[0],true),e);}
  else if (pos=='inside') {e.appendChild(document.importNode(new DOMParser().parseFromString(xml,'application/xml').childNodes[0],true));}
  else if (pos=='replace') {e.parentNode.replaceChild(document.importNode(new DOMParser().parseFromString(xml,'application/xml').childNodes[0],true),e);}
  //Add fragment and have it returned.
 }
}
Campos answered 3/1, 2020 at 15:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.