Integrating Sencha Touch and Hogan.js for Easy HTML Templating
I’ve been working with Sencha Touch lately and I’ve been impressed with it so far. It’s a really nice full-stack solution for HTML5 mobile web development. There was however a pain point I came across that I needed to solve.
Sencha Touch has a nice component called DataView that can dynamically render HTML based on a collection of data. With a DataView, you have the ability to specify a template (“itemTpl”) which is a chunk of HTML rendered for each element in the Store. Unfortunately the framework only supports declaring this in Javascript, so you are left with some pretty nasty syntax:
{
xtype: 'dataview',
margins: '5 5 5 5',
flex: 1,
scrollable: true,
store: 'MyData',
selectedCls: 'myDataSelected',
itemTpl : Ext.create("Ext.XTemplate",
'<div class="myData">',
'{LASTNAME}, {FIRSTNAME}<br />',
'{ADDRESS} <br />',
'{DESCRIPTION}<br />',
'</div>'
)
}
Fortunately I was able to hack together a quick and dirty workaround for this based off Hogan.js, Twitter’s Mustache-compatible HTML templating system. First I wrote a simple HTML template named myTemplate.mustache:
<div class="myData">
{{LASTNAME}}, {{FIRSTNAME}}<br />
{{ADDRESS}} <br />
{{DESCRIPTION}}<br />
</div>
Then I used Hogan’s “hulk” executable to compile the template to a Javascript file. If you have multiple templates, hulk will merge them into a single file. The template will be available in Hogan via its name, in this case “myTemplate”. The output of the file isn’t important nor is it very readable, so we’ll skip that part.
Then I edited my main HTML file to include the Hogan library and my compiled templates:
<script type="text/javascript" src="Hogan/template.js"></script>
<script type="text/javascript" src="app/tpl/hogan.templates.js"></script>
Next I wrote a subclass of Ext’s XTemplate to serve as an adapter between their template API and Hogan’s. I haven’t tested this very thoroughly yet; there are likely a bunch of other methods that need overriding to get this solid:
Ext.define("Hogan.HoganTemplate", {
extend: "Ext.Template",
_templateName: null,
constructor: function (config) {
this.param = config.param;
this._templateName = config.templateName;
this.callParent(arguments);
},
// Returns an HTML fragment of this template with the values applied.
apply: function (values) {
//: String
return templates[this._templateName].render(values);
},
// Appends the result of this template to the provided output array.
applyOut: function (values, out) {
//}: Array
},
//Alias for apply. ...
applyTemplate: function (values) {
//}: String
return apply(values);
},
});
And then updated the original code snippet to use the following:
{
xtype: 'dataview',
store: 'MyData',
margins: '5 5 5 5',
flex: 1,
itemTpl: Ext.create("Hogan.HoganTemplate", {templateName:"myDataTemplate"}),
selectedCls: 'myDataSelected'
}
and presto, it just works :)
Adapting this for Mustache.js should be straightforward provided they expose a similar API with a synchronous render() method.