best way to inject html using javascript

I'm hoping that this isn't too subjective. I feel there is a definitive answer so here goes.

I want to create this html on the fly using JS (no libraries):

<a href="#" id="playButton">Play</a>
<a href="javascript: void(0)" id="muteUnmute">Mute</a>
<div id="progressBarOuter"> 
  <div id="bytesLoaded"></div>
    <div id="progressBar"></div>
</div>
<div id="currentTime">0:00</div>
<div id="totalTime">0:00</div>

using javascript. I know I can do this using createElement etc but it seems extremely long winded to do this for each element. Can anyone suggest a way to do this with more brevity.

I do not have access to a library in this project....so no jquery etc.

Answers:

Answer

Shove the entire thing into a JS variable:

var html = '<a href="#" id="playButton">Play</a>';
html += '<a href="javascript: void(0)" id="muteUnmute">Mute</a>';
html += '<div id="progressBarOuter"><div id="bytesLoaded"></div><div id="progressBar"></div></div>';
html += '<div id="currentTime">0:00</div>';
html += '<div id="totalTime">0:00</div>';

Then:

document.getElementById("parentElement").innerHTML = html;

if you want theN:

document.getElementById("totalTime").innerHTML = "5:00";
Answer

Keep your markup separate from your code:

You can embed the HTML snippets that you'll be using as hidden templates inside your HTML page and clone them on demand:

<style type="text/css">
#templates { display: none }
</style>
...
<script type="text/javascript">
var node = document.getElementById("tmp_audio").cloneNode(true);
node.id = ""; // Don't forget :)
// modify node contents with DOM manipulation
container.appendChild(node);
</script>
...
<div id="templates">
    <div id="tmp_audio">
        <a href="#" class="playButton">Play</a>
        <a href="#" class="muteUnmute">Mute</a>
        <div class="progressBarOuter"> 
            <div class="bytesLoaded"></div>
            <div class="progressBar"></div>
        </div>
        <div class="currentTime">0:00</div>
        <div class="totalTime">0:00</div>
    </div>
</div>

Update: Note that I've converted the id attributes in the template to class attributes. This is to avoid having multiple elements on your page with the same ids. You probably don't even need the classes. You can access elements with:

node.getElementsByTagName("div")[4].innerHTML =
    format(data.currentTime);

Alternatively, you can act on the HTML of the template:

<script type="text/javascript">
var tmp = document.getElementById("tmp_audio").innerHTML;
// modify template HTML with token replacement
container.innerHTML += tmp;
</script>
Answer

You can use

<script type="text/javascript">
    function appendHTML() {
        var wrapper = document.createElement("div");
        wrapper.innerHTML = '\
<a href="#" id="playButton">Play</a>\
<a href="javascript: void(0)" id="muteUnmute">Mute</a>\
<div id="progressBarOuter"> \
<div id="bytesLoaded"></div>\
    <div id="progressBar"></div>\
</div>\
<div id="currentTime">0:00</div>\
<div id="totalTime">0:00</div>\
';
        document.body.appendChild(wrapper);
    }
</script>
Answer

Now with Web Components you can inject HTML using an HTML import.

The syntax looks like this:

<link rel="import" href="component.html" >

This will just load the content of the html file in the href attribute inline in the order it appears. You can any valid html in the loaded file, so you can even load other scripts if you want.

To inject that from JavaScript you could do something of the likes of:

var importTag = document.createElement('link');
importTag.setAttribute('rel', 'import');
importTag.setAttribute('href', 'component.html');
document.body.appendChild(importTag);

At the time I am writing this, Chrome and Opera support HTML imports. You can see an up to date compatibility table here http://caniuse.com/#feat=imports

But don't worry about browsers not supporting it, you can use it in them anyway with the webcomponentsjs polyfill.

For more info about HTML imports check http://webcomponents.org/articles/introduction-to-html-imports/

Answer

If you don't need any validation for your syntax (which is what makes createElement() so nice) then you could always default to simply setting the innerHTML property of the element you want to insert your markup inside of.

Personally, I would stick with using createElement(). It is more verbose but there are far less things to worry about that way.

Answer

You can concatenate raw HTML strings (being careful to escape text and prevent XSS holes), or you can rewrite jQuery (or something similar)

Answer

If performance is a concern, stay away from innerHTML. You should create the whole object tree using document.createElement() as many times as needed, including for nested elements.

Finally, append it to the document with one statement, not many statements.

In my informal testing over the years, this will give you the best performance (some browsers may differ).

If HTML is ever declared in a variable, it should be simple and for a very specific purpose. Usually, this is not the right approach.

Answer

I have a situation where I pass text into a third party library, but if my model isPrivate, I'd like to add an element to the text.

return { id: item.id, text: (item.isPrivate == true) ? "<i class=\"icon-lock\" title=\"Private group.\"></i> " + item.label : item.label };

This creates issues with the way the third party library builds up its markup.

This is never a good idea, but third party libraries are there so that we don't have to write everything ourselves. In a situation like this, you have to rely on passing markup though javascript.

When i find a proper solution to this, I will give you an update

Answer

If you live in 2019 and beyond read here.

With JavaScript es6 you can use string literals to create templates.

create a function that returns a string/template literal

function videoPlayerTemplate(data) {
    return `
        <h1>${data.header}</h1>
        <p>${data.subheader}</p>
        <a href="#" id="playButton">Play</a>
        <a href="javascript: void(0)" id="muteUnmute">Mute</a>
        <div id="progressBarOuter"> 
            <div id="bytesLoaded"></div>
            <div id="progressBar"></div>
        </div>
        <time id="currentTime">0:00</time>
        <time id="totalTime">0:00</time>
    `
}

Create a JSON object containing the data you want to display

var data = {
     header: 'My video player',
     subheader: 'Version 2 coming soon'
}

add that to whatever element you like

const videoplayer = videoPlayerTemplate(data);
document.getElementById('myRandomElement').insertAdjacentHTML("afterbegin", videoplayer);

You can read more about string literals here

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.