BorisMoore / jsrender

A lightweight, powerful and highly extensible templating engine. In the browser or on Node.js, with or without jQuery.
http://www.jsviews.com
MIT License
2.67k stars 339 forks source link

<template> instead of <script> #345

Closed sp00n closed 5 years ago

sp00n commented 5 years ago

Is there a way to use a <template> tag instead having to use <script>? The tag has been around since 2013, and browser support seems to be pretty good now. In the documentation it says that it's possible "to declare a template in a non-script element", although discouraged, because it could cause images to load incorrectly. For <template> tags this should avtually be a non issue, because its content is not rendered on page load anyway.

However when I try to use such a template with e.g. let myTmpl = $.templates("#template-tag-id");, I receive the following error: JsRender Error: #template-tag-id: Use script block, not TEMPLATE

There's a specific element check in jsrender.js, line 1112 that triggers this error:

if (elem.tagName !== "SCRIPT") {
    error(value + ": Use script block, not " + elem.tagName);
}
BorisMoore commented 5 years ago

A <template> tag does not render but its contents are supposed to be valid HTML markup, and are parsed and validated by the browser. That means that for both <template> and <div> tags, the browser may modify the contents (to try to make valid HTML), and so when the jsrender code calls innerHTML to get the template string, the result may be quite incorrect.

Try commenting out the line 1112 in jsrender.js, and use the following template:

<someElement ...>
<br/>
{{>myHTMLstring}}
</somelement>

Only <script ...> works correctly... The others transform the innerHTML to

<br>
{{&gt;myHTMLstring}}

I will change the text in the documentation to make it clearer:

Note: It is not possible to declare a template in a non-script element such as a <div>. JsRender throws an error if you try to do so. This is because the browser will process the <div> content as HTML, and in some cases, modify the template string. For example if the template includes a {{> ...}} tag, then the browser will change it to {{&gt; ...}} and the tag will not work…

sp00n commented 5 years ago

Yeah, I stumbled across the {{>varName}} as well and wondered why it wouldn't parse the data correctly. Bummer.

BorisMoore commented 5 years ago

It will also fail in many other cases which are not valid HTML. Text is not allowed between tr and td, or ul and li, etc. so <tr>{{for items}}<td>... is not valid. Not to mention things like {{if foo}}<div class="a">{{else}}<div class="b">{{/if}}, etc. etc.