How to use HTML <template> with variables (with Vanilla JS)

4.5k views Asked by At

Currently I'm doing the following:

This is my HTML template

<template id="catDisplayTemplate">
      <div class="col">
        <img class="mehow" src="{{catImg}}" alt="" data-name="{{catName}}" data-id="{{catId}}">
        <div class="row space-between">
          <div class="col">
            <p class="description">{{catDescription}}</p>
          </div>
       </div>
       </div>
</template>

The following code change the moustaches but it feels like repeating itself

const catTemplate = document.querySelector('#catDisplayTemplate').innerHTML;
catTemplate = catTemplate.replace(/{{catImg}}/g, catData.img);
catTemplate = catTemplate.replace(/{{catName}}/g, catData.name);
catTemplate = catTemplate.replace(/{{catId}}/g, catData.id);
catTemplate = catTemplate.replace(/{{catDescription}}/g, catData.description);

*catData is the object with the details.

Is there a better/other way?

1

There are 1 answers

0
Louise Eggleton On

You could write an interpolate function that accepts the template and an object containing the keys and values you want to replace. There are several examples in the answer to this question: Can ES6 template literals be substituted at runtime (or reused)?

Here is one that I use, which I borrowed from here: It sanitizes input against XSS attack and replaces placeholders with variables. I am likely to split this into separate functions for production use.

interpolate(template, params) {
    const replaceTags = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '(': '%28', ')': '%29' };
    const safeInnerHTML = text => text.toString().replace(/[&<>\(\)]/g, tag => replaceTags[tag] || tag);
    const keys = Object.keys(params);
    const keyVals = Object.values(params).map(safeInnerHTML);
    return new Function(...keys, `return \`${template}\``)(...keyVals);
 }

You would use it like this:

const template = document.querySelector('myTemplate')
const data = { name: 'John Doe', age: 25}    
someDiv.innerHTML = interpolate(template.innerHTML.toString().trim(), data)