Debo admitir que siempre me ha resultado pesado y aburrido integrar recursos no programados por mí en mi stack de trabajo, por eso muchas de las funciones y utilidades son de mi autoría.

Hace algún tiempo fuimos contratados por un cliente para la creación de un proyecto que requería panel para creación y actualización de contenido, aplicación para móviles y aplicación para web. Uno de los puntos fuertes de este proyecto eran las listas puesto que involucraba catálogo de productos.

Estuve revisando varios templates engines para el front-end, entre ellos EJS, mi favorito cuando desarrollo para NodeJS. Probe varios más que desconocía pero todos coincidian en el mismo punto: Ofrecían muchísimo más de lo que necesitaba.

De ahí nació xTemplateDOM, una función escrita en JavaScript vanilla:

function xTemplateDOM (parms)
{
    var template_selector = parms['template_selector'] || '';
    var template_string = parms['template_string'] || '';
    var data = parms['data'] || [];
    var htm = '', tpl = '';

    data = (Array.isArray(data)) ? data : [data];

    if ( (template_string || template_selector) && (data.length > 0) )
    {
        if ( template_string )
        {
            tpl = String(template_string).replace(/(\r\n|\n|\r|\s+)/gm,' ');
        } else {
            tpl = String(document.querySelector(template_selector).innerHTML).replace(/(\r\n|\n|\r|\s+)/gm,' ');
        };

        tpl = tpl.replace(/(@\{)\s*(\S+)\s*(?=})/img,'$1$2');

        for (var i = 0, c = data.length; i < c; i++)
        {
            var row = data[i], str = tpl;

            for (var k in row)
            {
                var key = k, val = row[k];

                var rgx = new RegExp('@{' + key + '}','img');
                str = str.replace(rgx,val);
            };

            htm += str + '\n';
        };
    };

    return htm;
};

Integrarla en el proyecto es de lo más sencillo. Agregamos la porción del template como parte del DOM pero escondido con un script tag:

<!DOCTYPE html>
<html>
    <head>
        <title>My xTemplateDOM test</title>
    </head>
    <body>

        <ul id="box">
            ...
        </ul>

        <script type="text/templatedom" id="template-profile">
            <li data-profileid="@{profileid}">
                <div>
                    <span>Firstname:</span>
                    <span>@{firstname}</span>
                </div>
                <div>
                    <span>Lastname:</span>
                    <span>@{lastname}</span>
                </div>
            </li>
        </script>

    </body>
</html>

Finalmente llamamos el template y lo alimentamos con la data de nuestra lista:

var actors = [
    {
        profileid: 3321,
        firstname: 'Bruce',
        lastname: 'Willis'
    },
    {
        profileid: 4318,
        firstname: 'Angelina',
        lastname: 'Jolie'
    },
    {
        profileid: 7269,
        firstname: 'Robert',
        lastname: 'De Niro'
    }
];

document.querySelector('#box').innerHTML = xTemplateDOM({
    template_selector: '#template-profile',
    data: actors
});

También podemos pasar el template como parte de la llamada sin necesidad de tocar el DOM:

var actors = [
    {
        profileid: 3321,
        firstname: 'Bruce',
        lastname: 'Willis'
    },
    {
        profileid: 4318,
        firstname: 'Angelina',
        lastname: 'Jolie'
    },
    {
        profileid: 7269,
        firstname: 'Robert',
        lastname: 'De Niro'
    }
];

document.querySelector('#box').innerHTML = xTemplateDOM({
    template_string: '<li data-profileid="@{profileid}">@{firstname} @{lastname}</li>',
    data: actors
});

Además de lista de objetos también podemos pasar la data de solo un objecto. Es obvio, porque no todo el tiempo necesitamos alimentar listas.

document.querySelector('#box').innerHTML = xTemplateDOM({
    template_selector: '#template-profile',
    data: {
        profileid: 7269,
        firstname: 'Robert',
        lastname: 'De Niro'
    }
});

document.querySelector('#box').innerHTML = xTemplateDOM({
    template_string: '<li data-profileid="@{profileid}">@{firstname} @{lastname}</li>',
    data: {
        profileid: 7269,
        firstname: 'Robert',
        lastname: 'De Niro'
    }
});

Creo xTemplateDOM es simple de implentar pero si te queda alguna inquietud la puedes dejar en los comentarios, que con gusto te responderé.