DOM tree based JavaScript template engines - javascript

I am looking for a new Javascript template engine to replace old jQuery Template for my client side templating needs.
I'd prefer approach where the template engine deals with DOM trees instead of text strings and later dumps the content of the cooked string into innerHTML. This is better performance wise and I find DOM manipulation more proper way of constructing more of DOM tree.
What options I do have for Javascript template engine which would directly create DOM trees instead of being text based engines? I like Mustache.js's logicless approach, but it seems to operate on strings only. Native jQuery integration would also be a nice feature.

Transparency:
https://github.com/leonidas/transparency/
PURE:
http://beebole.com/pure/documentation/
Plates
https://github.com/flatiron/plates
Why all this:
http://blog.nodejitsu.com/micro-templates-are-dead

Distal
http://code.google.com/p/distal

soma-template is a new one.
Pure DOM manipulation, a lot of features, natural syntax, fully extensible with other libraries such as underscore.string, function calls with parameters, helpers, watchers. Capability to update only some nodes if needed, templates inside the DOM itself.
http://soundstep.github.com/soma-template/

This is good comparison about 7 famous JS template engine: http://blog.stevensanderson.com/2012/08/01/rich-javascript-applications-the-seven-frameworks-throne-of-js-2012/

I've recently created DOM templating engine inspired by PURE and Transparency.
It supports loops, conditions and much more.
Take a look at doc: http://code.meta-platform.com/metajs/components/template/
Don't be affraid that MetaJS is big library, templating lib can be used standalone.
Short example:
HTML:
<div id="tpl">
<ul id="tasks">
<li>
<span class="task"></span>
<span class="due-date"></span>
</li>
</ul>
</div>
Define template:
var tpl = Meta.Template(document.getElementById('tpl'), {
"ul#tasks li": $__repeat("tasks", {
".task": "task",
".due-date": $__date("d. m. Y", "due_date"),
"#": $__attrIf("completed", "complete")
})
});
Render template:
tpl({
tasks: [
{
task: "Write concept",
due_date: new Date(2015, 3, 22, 0, 0, 0, 0),
complete: true
}, {
task: "Consult with customer",
due_date: new Date(2015, 3, 25, 0, 0, 0, 0),
complete: false
}
]
});
Result:
<div id="tpl">
<ul id="tasks">
<li>
<span class="task" completed>Write concept</span>
<span class="due-date">22. 3. 2015</span>
</li>
<li>
<span class="task">Consult with customer</span>
<span class="due-date">25. 3. 2015</span>
</li>
</ul>
</div>

Take a look at Monkberry DOM template engine.
It is really small (just 1,5kB gzipped), dependency free library, server compiling, one-way data binding, and it's dramatically fast!
Here example of template and generated code:
<div>
<h1>{{ title }}</h1>
<p>
{{ text }}
</p>
</div>
Will generate:
var div = document.createElement('div');
var h1 = document.createElement('h1');
var p = document.createElement('p');
div.appendChild(h1);
div.appendChild(p);
...
view.update = function (data) {
h1.textContent = data.title;
p.textContent = data.text;
};
Monkberry supports if, for and custom tags. And has a lot of rendering optimizations.
Templates can be rendered on server with webpack, browserify or cli.
monkberry.js.org

dna.js is a templating engine that clones DOM elements (https://dnajs.org).
Example template for a book:
<h1>Featured Books</h1>
<div id=book class=dna-template>
<div>Title: <span>{{title}}</span></div>
<div>Author: <cite>{{author}}</cite></div>
</div>
Call to insert a copy of the template into the DOM:
dna.clone('book', { title: 'The DOM', author: 'Jan' });
Resulting HTML:
<h1>Featured Books</h1>
<div class=book>
<div>Title: <span>The DOM</span></div>
<div>Author: <cite>Jan</cite></div>
</div>
Fiddle with a sample "To-Do Application":
https://jsfiddle.net/uLrc7kmp
dna.js was created precisely to avoid constructing and passing around string templates (I'm the project maintainer).

Free MIT-licensed jQuery DNA Template with superpowers (you can re-apply the changed data to the same HTML structure to update UI on any data change...)
https://github.com/webdevelopers-eu/jquery-dna-template/

What sort of sugar are you looking for? The raw DOM api always worked fine for me. If you are really adopting this idea that the templating engines are no good in terms of performance, don't use innerHTML if you want to efficiently build up a DOM tree. What I tend to do is just create elements manually using document.createElement. My templates are created by writing helper functions that create collection of nodes and populate them with the data by setting the .innerText property. I can then cache the references to nodes which I wish to refer to frequently so that I don't have to traverse the DOM tree to find these nodes again.

Related

Set HTML template tag content without JavaScript selectors

Let's say we have the following HTML template:
<template id="my_template">
<div>
<h4>Test Titel</h4>
<div class="row">
<label for="someinput">Stichwort:</label>
<input id="someinput" type="text"/>
</div>
</div>
</template>
Now I like to render a list with multiple items based on that template.
I know that we can just clone the template and use selectors on it as on a regular DOM.
But is there also an alternative way to clone, etc... but with data, so that we can set the content without using selectors, but variables?
Something like the following, we just declare the variable ID before adding the template?
<template id="my_template">
<div>
<h4>Test Titel</h4>
<div class="row">
<label for="someinput_${ID}">Stichwort:</label>
<input id="someinput_${ID}" type="text"/>
</div>
</div>
</template>
I know it is possible with template literals, but I am just curious if this also works in any way with theses handy template tags?
Is it at all possible to set data in a temple tag without using selectors on it?
Is it at all possible to set data in a temple tag without using sectors on it ?
No, not in the way you mean. (The literal answer to the question quoted above is "yes" but only because you can modify the DOM without using selectors, per se — by doing the DOM traversal yourself. Not a useful "yes." 🙂 )
HTML template tags don't have an "evaluate with these variables" method or similar. As you've said in the question, you could always write a function that uses a JavaScript template literal to build the HTML instead (and then use insertAdjacentHTML() or innerHTML to add it to the DOM).

How to use components in v-html

I am trying to use components in v-html.
I want to get html from own API, then I will show that.
Here is my code.
HTML:
<!-- app -->
<div id="app">
<span v-html="html"></span>
<badge></badge>
<span v-html="html2"></span>
<partial name="my-partial"></partial>
<span v-html="html3"></span>
</div>
Javascript:
Vue.component('badge', {
template: '<span class="component-tag">This is component</span>',
})
Vue.partial('my-partial', '<p>This is a partial!</p>')
// start app
new Vue({
el: '#app',
data: {
html: '<p>THIS IS HTML</p>',
html2: '<badge></badge>',
html3: '<partial name="my-partial"></partial>'
}
})
https://jsfiddle.net/9w3kz6xm/4/
I tried partials because Vue document says " If you need to reuse template pieces, you should use partials."
It does not work. Maybe I am making mistake, I don't know what is a mistake.
Thank you.
Pretty sure Vuejs makes it very hard to directly use external html. v-html will simply replace the html content and therefore will not execute any directive. The purpose of it is to avoid XSS attacks as documented here: https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML
Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS vulnerabilities. Only use HTML interpolation on trusted content and never on user-provided content.
If you really need to use external html, it is possible to use Vue.compile() documented here: https://v2.vuejs.org/v2/api/#Vue-compile
A working example can be found here: https://jsfiddle.net/Linusborg/1zdzu7k1/
and its related discussion can be found here: https://forum.vuejs.org/t/vue-compile-what-is-staticrenderfns-render-vs-staticrenderfns/3950/7

Kendo UI - Localize application

How does one localize a pure front-end application that uses a framework such as Kendo UI ?
I mean, it's possible to do something like this:
$(document).ready(function(){
$("#myText").html(<grab text based on language>);
});
But then, if I have a listview and want to localize its title:
<div id="tabstrip-expenseaccounts" data-role="view">
<ul data-role="listview" data-style="inset" data-type="group">
<li id="expenseaccounts-listview-title">
abcde
<ul>
...
</ul>
</li>
</ul>
</div>
Becomes:
...
<li id="expenseaccounts-listview-title" class="km-group-container">
<div class="km-group-title">
<div class="km-text">abcde</div>
</div>
<ul class="km-list">
...
</ul>
</li>
...
I need to inspect the generated code and do something like:
$(document).ready(function(){
$("#expenseaccounts-listview-title.km-group-container div.km-group-title div.km-text").html(<grab text based on language>);
});
It works fine, but that doesn't seem like a clean solution to me.
Any advice ? Thanks!
For KendoUI there some language packs available on GitHub here. This other stakoverflow question should give you a headstart. With this, all you have to do is use the correct language pack and you're good to go. And if there is no language pack for your specific case, you can always roll your own.
Hope this helps.
While I have not found a solution proper to Kendo UI, here is the approach I went for to localize my mobile application. Note here that I am not talking about localizing widgets, I am referring to localizing every static aspect of the application: input placeholders, texts on buttons, headings, etc.
My mobile application only has one file, index.html, and whenever I want to navigate to a different page, i simply move to a different view. Since having multiple views in the same file is kind of a mess, I made one html file per view, and am dynamically loading them into the body (index.html has an empty body). Before appending the html which is retrieved using $.get for each view (at this point, it's a huge string), i am replacing text based on the current language (which is retrieved from the localstorage/cookie or from a default value).
example:
In my localization library:
_localization.localizeText = function(text, arr){
arr.forEach(function(item){
text = text.replace(item.name, getLang() == 1 ? item.replacement.en : item.replacement.fr);
});
return text;
}
In my login.html file:
<button>$$login-button$$</button>
And then in some javascript file which is included before the script in which the application is initialized:
var replacements = [];
replacements.push({
name: "$$login-button$$",
replacement: {
fr: "Connecter",
en: "Log In"
}
});
And then when i'm loading my files into the body:
$.when($.get("login.html"))
.done(function(p1){
var body = $("body");
body.append(localization.localizeText(p1[0], app.replacements));
});
Hope this helps anyone with similar issues!

Dojo HTML template: repeating a piece of HTML inside the HTML template

I have a template based dojo widget, and a HTML template for it, in a separate .html file.
The Dojo Widget:
define("dojow/SomeWidgetName",[
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dojo/text!./templates/MyHTMLFile.html"], function(declare, _WidgetBase, _TemplatedMixin, template) {
return declare([_WidgetBase, _TemplatedMixin], {
templateString: template,
baseClass: 'dojowBaseClass',
details:{} // THIS IS THE OBJECT THAT WILL BE LOOPED
// your custom code goes here
});});
The HMTL template:
<table>
<tr>
<td>SomeService</td>
<td>someUsername</td>
</tr> </table>
What I need is to repeat the row of the table based on the "details" object I am having inside the dojo widget, so each row contains data from that object. Is that possible?
Thanks.
As far as I know: no. The templating language of Dojo is very basic and just offers attach points/events that you can use to programmatically change it. It's one of the shortcomings/weaknesses of Dojo (compared to templating engines like Handlebars), even ex-core-commiters think that way.
So, an alternative approach to create a loop structure is programmatically creating one. Let's say our template is the following:
<ul data-dojo-attach-point="listNode"></ul>
Then you can do the following in your code:
domConstruct.create("li", {
innerHTML: "test"
}, this.listNode);
That will result in the following HTML:
<ul data-dojo-attach-point="listNode">
<li>test</li>
</ul>
So you can put that inside a loop in your code (and create many child items), but as you can see, the template language itself is lacking such a feature.
If you want to load "a template", you can define a child item template, and load it using:
domConstruct.place(lang.replace("<li>{text}</li>", {
text: "test"
}), this.listNode);
Small note: The dojo/_base/lang is inconsistent with the widget templating. Placeholders in a templated widget are written like ${placeholder, but in dojo/_base/lang a placeholder is defined as {placeholder} (without the dollar sign).

Using agility.js for page layout and composition

I am new to MVC-style javascript libraries, so pardon me if this question is too basic. I'm trying to write a Single-Page Application entirely in jQuery and agility.js. The examples given in the agility.js documentation consist entirely of adding html elements to the document root. Question: Is there a 'Best-Practices' way to assemble a page by components.
Here is a rough outline of my html app:
<html>
<head> ... </head>
<body>
<header> ... </header>
<div id=PageHolder>
<div id=AppPane_1></div>
<div id=AppPand_2></div>
</div>
<footer> ... </footer>
</body>
</html>
Within the 'AppPane' divs will be the content of the application.
Okay, given all of this, I'm not asking what can I do, but I'm asking what should I do.
I see from the documentation and my research that I have 3 choices:
create my page composition from atomic agility objects and assemble them in a jQuery document ready block. $$.document.append(Foo) works for the root element, but I could not figure out how to add Foo's children to foo.
Use one (very large) agility object which lays out the basic static html from above and append controls and whatnot to that using the controller functions (which I havn't been able to get to work either)
Use one root agility object and append all the children onto it using view (somehow, I havn't been able to get that to work either.)
Which of these is best, and what is the syntax involved? Thanks in advance, any guidance in assembling html components into a cogent agility app would be much appreciated.
http://jsbin.com/ojenon/1/
In my opinion, the best way to organize your page modules is to save individual client-side templates in script tags in the head:
<html>
<head>
<script type="text/template" id="template1">
<b>Some <abbr>HTML</abbr> template</b>
</script>
<script type="text/template" id="template2">
<b>Some <abbr>HTML</abbr> template</b>
</script>
</head>
...
You could even choose to use a template language, such as jQuery.template or handlebars.js, to facilitate logic, variable interpolation, etc.
Then, in your your controller, you would load the html contents of these templates' script tags from the DOM and copy them into your destination div (#PageHolder) as appropriate.
An alternative to this technique would be storing your templates in a literal JS object in the head:
<script type="text/javascript">
var Templates = {
template1: "<b>Some <abbr>HTML</abbr> template</b>"
...
}
</script>
This is just the beginning. There are many more options, such as pre-compiling your templates, subdividing your templates to avoid redundant template compilations, etc. From a structural standpoint, maintaining your templates in a dedication location will help you scale your single page app.
It's horses for courses I guess, but my preference is to have the template code alongside the Agility code so that it's all visible together. I don't particularly like seeing the html and styling inside the view object, but you can set these up in other variables and reference them in the view like this:
var frmMainTemplate = '<div>' +
'<input type="text" data-bind="name" />' +
'<p>You typed <span data-bind="name" /></p>' +
'</div>';
var frmMainStyle = '& span {background-color:#888; color:#fff;}';
var frmMain = $$({
model: {name:''},
view: {
format: frmMainTemplate,
style: frmMainStyle
},
controller: {}
});
$$.document.append(frmMain);

Categories

Resources