There are many template engines but my question is: Why do they still exist? Can we not achieve the same job with readily available JavaScript Template Literals?
So influenced from this blogpost, I have come up with something as follows. Do you think this is reasonable in daily JavaScript?
The following code is pure JavaScript. Lets start with a proper data.
var data = { labels: ['ID','Name']
, rows : [ {"id": "1", 'name': "richard"}
, {"id": "2", 'name': "santos"}
]
};
Now let's define a tableTemplate
function which takes the data
and gives us an HTML table.
function tableTemplate(data){
return `
<table>
<tr> ${data.labels.map(label => html`
<th>&${label}</th>`).join("")}
</tr>${data.rows.map(row => html`
<tr>
<td>&${row.id}</td>
<td>&${row.name}</td>
</tr>`).join("")}
</table>`;
}
So what is this html`
thingy and also that &$
?
- First of all
html`
is just a generic tag function that we define only once and without modifying it, we can use it for all of our template functions. &$
on the other hand is simple.&
is just a simple string character and the second one is the escaping$
character for variables in template strings such as${x}
. We can use a tag function to validate our HTML code by escaping invalid HTML characters like&
,>
,<
,"
,'
or`
. The version I give below looks a little convoluted but it's really simple and very useful. It basically escapes invalid HTML characters and provides a "raw" version of the template string.
Please follow above links for further information. Here it is:
function html(lits,...vars){
var esc = { "&": "&"
, ">": ">"
, "<": "<"
, '"': """
, "'": "'"
, "`": "`"
};
return lits.raw
.reduce( (res,lit,i) => (res += lit.endsWith("&") ? lit.slice(0,-1) + [...vars[i].toString()].reduce((s,c) => s += esc[c] || c, "")
: lit + (vars[i] || ""))
, ""
);
}
Now, it's time to put everything together for a working sample. Let's also add <thead>
and <tbody>
tags and some CSS this time.
function html(lits,...vars){
var esc = { "&": "&"
, ">": ">"
, "<": "<"
, '"': """
, "'": "'"
, "`": "`"
};
return lits.raw
.reduce( (res,lit,i) => (res += lit.endsWith("&") ? lit.slice(0,-1) + [...vars[i].toString()].reduce((s,c) => s += esc[c] || c, "")
: lit + (vars[i] || ""))
, ""
);
}
function tableTemplate(data){
return `
<table>
<thead>
<tr>${data.labels.map(label => html`
<th>&${label}</th>`).join("")}
</tr>
</thead>
<tbody>${data.rows.map(row => html`
<tr>
<td>&${row.id}</td>
<td>&${row.name}</td>
</tr>`).join("")}
</tbody>
</table>`;
}
var data = { labels: ['ID','Name']
, rows : [ {"id": 1, 'name': "richard"}
, {"id": 2, 'name': "santos"}
, {"id": 3, 'name': "<ömer & `x`>"}
]
};
document.write(tableTemplate(data));
table {
background-color: LightPink;
border : 0.2em solid #00493E;
border-radius : 0.4em;
padding : 0.2em
}
thead {
background-color: #00493E;
color : #E6FFB6
}
tbody {
background-color: #E6FFB6;
color : #00493E
}
Obviously you can now insert <style>
tag or class="whatever"
attribute into your quasi-HTML template literal in the tableTemplate
function just the way you would normally do in an HTML text file.
Also please note that if you console.log
the resulting HTML text string, thanks to the raw conversion, it would beautifully display (according to your indenting in the tableTemplate
function) just like below:
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>richard</td>
</tr>
<tr>
<td>2</td>
<td>santos</td>
</tr>
<tr>
<td>317</td>
<td><ömer & 'x'></td>
</tr>
</tbody>
</table>
data
? \$\endgroup\$tableTemplate
function in the working sandbox is exactly the same one as shown in the second snippet. When i try to edit it just turns back into how i had written it and works just fine until i save it and it shows again that silly hash code<th>{cbe533db-4533-4fed-934e-f25c95923264}{row.name}</td>
. What's happening..? Perhaps the$$
is colliding with some parsing library behind the curtain..? \$\endgroup\$$$
with&$
in my code and the sandbox bug is resolved. So.. i guess somebody has to fix something. From this bug only i can conclude that the Stackoverflow and Codereview sandboxes are of different sources or versions of the same source since my code's original form works just fine @ SO. \$\endgroup\$$$
and it worked fine,. Most likely something your end (extension or the like) inserting the GUID \$\endgroup\$edit the above snippet
link and replace&$
s with$$
s in the sandbox everything still works just fine but only after you save it with$$
then things show up awry in the question. \$\endgroup\$