17

I need to append some html to an existing element using pure javaScript:

function create(htmlStr) {
  var frag = document.createDocumentFragment(),
    temp = document.createElement('div');
  temp.innerHTML = htmlStr;
  while (temp.firstChild) {
    frag.appendChild(temp.firstChild);
  }
  return frag;
}

var target = document.querySelectorAll(".container-right");
var fragment = create(
  '<div class="freetext"><p>Some text that should be appended...</p></div>'
);
document.body.insertBefore(fragment, document.body.childNodes[0]);

It's kind of working, but I have two questions:

  1. How can I make sure that the html fragment is appended to the div with the class container-right and not just the body? Changing the last line to document.body.insertBefore(fragment, target); doesn't work.

  2. How can I insert the html after the content in the target element - after the existing content - like jQuery's append()?

Any help is much appreciated.

JsFiddle here.

Meek
  • 2,796
  • 7
  • 35
  • 57
  • You might be better off creating a div (`var div = document.createElement('div');`), setting its html (`div.innerHTML = "Hello World!";`), and appending it to the body (`document.body.appendChild(div);`) – Marie Feb 28 '17 at 20:04
  • 1
    `document.querySelectorAll()` returns a [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList), so you'll want `document.body.insertBefore(fragment, target[0]);`. – Elliot Bonneville Feb 28 '17 at 20:04

4 Answers4

30

Well, I know this works:

let elem = document.querySelector ( 'css-selector (id or class)' )

That should give you your element. Then you do this:

elem.innerHTML = elem.innerHTML + myNewStuff;

That'll append your html to the innerHTML of the element. I tried it quickly, it works.

Tim Consolazio
  • 4,621
  • 2
  • 17
  • 26
  • 5
    Be careful modifying the innerHTML property of an existing element directly. It may cause issues with any events bound to child-objects. – Marie Feb 28 '17 at 20:06
  • Yah agreed, you should always be mindful when directly manipulating DOM elements. I personally prefer using documentFragment, but as long as you know what you're doing this works. Unless I had a very good reason to, I wouldn't do this for an interactive element, only an element that displays static stuff. – Tim Consolazio Feb 28 '17 at 20:07
  • 1
    @TimConsolazio, thanks, it works. Can you elaborate on documentFragment, please? – Meek Feb 28 '17 at 20:09
  • 1
    documentFragment and the API it affords is the same idea as manipulating XML as a string (which is more or less what we're doing here) vs. using nodes to manipulate a parse-able structure in an object oriented way (more or less). If you look up "document.createDocumentFragment" you'll see what it's all about. In the vanilla JS world it is a very powerful way to work with creating, structuring, altering, and moving around HTML elements. Definitely a more robust way than messing around with innerHTML of live, currently displayed DOM elements (and higher performance if I recall correctly). – Tim Consolazio Feb 28 '17 at 20:12
  • Thanks for taking your time to elaborate on this. Much appreciated. – Meek Feb 28 '17 at 20:16
  • 1
    No problem at all, glad to help. – Tim Consolazio Feb 28 '17 at 20:16
  • 3
    Ammm `elem.innerHTML += myNewStuff;` seems more readable and simpler. – Roko C. Buljan Mar 30 '20 at 12:19
  • Ammm then set up a helpful edit suggestion (I certainly hope you don't say Ammm in your code reviews). – Tim Consolazio Mar 30 '20 at 12:28
26
var target = document.querySelector(".container-right");

var p = document.createElement('p');
p.innerHTML = "Some text that should be appended...";

var div = document.createElement('div');
div.appendChild(p);

var fragment = document.createDocumentFragment();
fragment.appendChild(div);

target.appendChild(fragment);

JSFiddle

Paulo Pereira
  • 982
  • 6
  • 15
  • This is MUCH more performant than the accepted answer. If you're dealing with a large element, the browser will re-render the entire thing rather than just the element you're appending. – Christopher May 14 '19 at 18:15
  • The accepted answer does point out/suggest document fragment, followed a couple of minutes later by this one... – Tim Consolazio Mar 30 '20 at 12:29
  • The problem with this solution is references, when element is appended, p, div, and fragment variables are now a dom references, so, if you modify one of them after appended, dom will be modified too, and that is something I dont expect, if I am dinamically generating multiple items (duplicates) then will fail because there will be just one element, instead N elements. – Máxima Alekz Jan 10 '21 at 08:06
  • @MáximaAlekz there is no sense in your comment. First, the question is not about multiple items. Second, it is the best thing to have dom reference because you can modify without querying again for the element. And last, answering you, if you have multiple items, declare multiple variables or reuse the same variable after appending (if you don’t care about the dom). – Paulo Pereira Jan 10 '21 at 14:02
7

Try this:

var target = document.querySelector(".container-right");
target.innerHTML += '<div class="freetext"><p>Some text that should be appended...</p></div>';
Justin Taddei
  • 1,799
  • 1
  • 14
  • 26
2

Based on this answer to a similar question, I have found that insertAdjacentHTML is a good fit for this kind of problems. I haven't tested it on a Node List, but with a single node it works perfectly.

insertAdjacentHTML has a great browser compatibility (back to IE4), plus it lets you decide where you want to insert the HTML (see here).

var target = document.querySelector(".container-right");
var newContent = '<div class="freetext"><p>Some text that should be appended...</p></div>';
target.insertAdjacentHTML('beforeend', newContent);
Giorgio Tempesta
  • 1,390
  • 19
  • 28