run_the_race
run_the_race

Reputation: 2368

Vanilla JS: Rendering a <template> tag with a Javascript object

Say one has an html template like this:

<template id="template">
    <div id="A"></div>
    <div id="B"></div>
    <div id="C"></div>
    <div id="D"></div>
    <div id="E"></div>
    <div id="F"></div>
</template>

Now when one clones to add it to the DOM with JavaScript, I have not come across a "nice" way to fill in all the blanks, this seems very verbose:

const object = {A:1, B:2, C:3, D:4, E:5, F:6};
const template = document.getElementById("template")
let newThing = template.cloneNode(true);
newThing.getElementById("A").innerHTML = object.A;
newThing.getElementById("B").innerHTML = object.B;
newThing.getElementById("C").innerHTML = object.C;
newThing.getElementById("D").innerHTML = object.D;
newThing.getElementById("E").innerHTML = object.E;
newThing.getElementById("F").innerHTML = object.F;
container.appendChild(newThing);

I understand one could drop the <template> and move it all into JavaScript, but I am hesitant, because I like to keep HTML in HTML files, then you have linting in the text editor etc..

To me this is not a great solution since now the HTML is living in script files:

const newThing = `
<div>
    <div>${object.A}</div>
    <div>${object.B}</div>
    <div>${object.C}</div>
    <div>${object.D}</div>
    <div>${object.E}</div>
    <div>${object.F}</div>
</div>

Is there a better way to render a template with an object of data? I have read up on lithtml, but a whole library to do this one little thing seems like overkill.

Upvotes: 0

Views: 1006

Answers (2)

Dave Pritlove
Dave Pritlove

Reputation: 2687

The object's key-value pairs can be used directly inside a for-in loop. This allows markup stored in an object of anylength to be assigned to an html collection where each element's ID is the same as the key value of the corresponding data object.

for (const property in object) {
newThing.getElementById(property).innerHTML = object[property];
}

In the above code, 'property' is the key name of each of the objects properties and so object[property] is a direct reference to its value.

I've used this in a working snippet below to render some arbirary html stored in an object:

const container = document.getElementById("container");

const object = {
  A:"<h2>my heading</h2>", 
  B:"<a href='https://www.google.com'>Google Search</a>", 
  C:"<p>Computing is enjoyable <i>and</i> frustrating<p>", 
  D:"<div> what\'s your name ? <input type='text'></div>", 
  E:"<p>another paragraph</p>", 
  F:"<h2>goodbye!</h2>"
}
const template = document.getElementById("template")
let newThing = template.content.cloneNode(true);

for (const property in object) {
newThing.getElementById(property).innerHTML = object[property];
}

container.appendChild(newThing);
<template id="template">
    <div id="A"></div>
    <div id="B"></div>
    <div id="C"></div>
    <div id="D"></div>
    <div id="E"></div>
    <div id="F"></div>
</template>

<div id="container"></div>

Upvotes: 1

Sir Archibald Humphrey
Sir Archibald Humphrey

Reputation: 339

This is one possible solution, however it is not exactly advised depending on what you are trying to do

If you'd like, you can create a template with an ID in your HTML like so:

<template id="myTemplate">
        <div>${object.A}</div>
        <div>${object.B}</div>
        <div>${object.C}</div>
        <div>${object.D}</div>
        <div>${object.E}</div>
        <div>${object.F}</div>
</div>

And then call eval inorder to parse it

eval('`' + document.getElementById("myTemplate").innerHTML + '`')

This returns the formatted code that you can then place in your document

Why shouldn't you use this?

Eval is pretty dangerous, and if used wrong someone can execute dangerous commands on behalf of your website. If this is some personal project you can use this if you'd like, but preferably not on some larger scale public use website.

Upvotes: 0

Related Questions