A Flight mixin for Handlebars templating with Components.
With Bower:
$ bower install --save flight-handlebars-view
With npm:
$ npm install flight-handlebars-view --save-dev
This project provides a mixin
for Flight.js components to use so they can implement all or part of their DOM behavior using Handlebars.js client-side templates. It is not a Component by itself.
A number of other flight templating mixins for Hogan, Mustache and others include a full Component piece along with a Mixin. They do this to abstract the entire managing of templates to a data/utility type mixin that attaches to the DOM and then listens for requests for templates from UI Components. The templates, rather their rendered html, is then sent back to the requesting UI Component via an event.
This approach has the drawback of tightly coupling the utility, template serving Component to any UI Component that wants to use the Mixin to render templates. Not to mention it makes us add another Component to the page and generate more events when the UI is rendering.
The approach taken here is to remove the data/utility Component all together, and thereby remove any dependency for other UI Components that want to use Handlebars templates to manage their DOM behavior. Let the UI Component manage their templates directly, as you already have Handlebars included on the page in the first place.
This mixin can be used with Flight.js via Require.js or using standalone Flight.js.
You only need to include/require Handlebars.js library (full or just the runtime if using only pre-compiled templates) for this mixin to work.
Use the with_handlebars_view
mixin. The mixin provides any Component with a render()
method. Then render method has the following signature:
- {string} html = this->render({string} name, {object} context)
Where:
-
{string} name - the property in
this.attr.templates
that references the specific template. A template can be referenced as any of the following:- an inline, string template
- an '#' id selector referencing a template in a
<script>
tag - the name of a pre-compiled template function
any template may contain partials, and even inline string templates can be partials as long as their property name is referenced as the partial (see example below).
-
{object} context - an object containing the context data to be used to render the template.
Use the templates()
method to define the templates and partials that your component will use.
You can define templates that refer to external templates (via <script>
tags), plain string/HTML templates and pre-compiled templates. For the first two, you can also pass in compile options for each template as well, which is the same object/options accepted by Handlebars.compile()
.
external <script>
templates
this.after('initialize', function() {
this.templates({
// references <script id="hello" ...>
'hello': '#hello',
// with Handlebars.compile options
'users': [ '#user-list', { noEscape: true }]
});
});
string/html templates
this.after('initialize', function() {
this.templates({
'hello': '<h1>{{greeting}}</h1>',
'user': [ '<li>{{name}} - {{age}}</li>', { noEscape: true }]
});
});
pre-compiled templates You can load your pre-compiled templates however you like, just use the actual template name as the value for the template property you setup. Pre-compiled templates can be setup as an array passing in compile options, as they're already compiled on the server side.
this.after('initialize', function() {
this.templates({
// references Handlebars.templates.hello
'hello': 'hello',
});
});
Use the templateHelpers()
method to define Handlebars helpers to be used in your templates. Be sure and set these up before calling render()
in your component.
Helpers are passed in as an object, where the property name is the Handlebars helper name to use. For example:
this.templateHelpers({
'json': function(obj) {
// return JSON formatted object
return new Handlebars.SafeString(JSON.stringify(obj));
}
});
Defining templates via
this.defaultAttrs()
ofthis.attributes()
in thetemplates
property is deprecated; but will still work. Use thetemplates()
method to define the templates for your component.
Examples of deprecated way of setting up templates via a components attributes:
this.defaultAttrs({
templates: { /*...*/ }
});
this.attributes({
templates: { /*...*/ }
});
The following gives an example shows each of the above use-cases within one UI Component.
Example using Flight standalone:
<!-- 1.) load pre-compiled templates from external file (from list-component.hbs) -->
<script src="pre-compiled.js"></script>
<!-- 2.) handlebars templates via SCRIPT tags (w/ partial) -->
<script id="list" type="text/x-template-handlebars">
<ul>
{{> item}}
</ul>
</script>
<!-- component node -->
<div id="list-component">
</div>
<!-- Define a component using this mixin -->
<script>
var ListComponent = (function() {
return flight.component(function() {
this.defaultAttrs({
title: '',
items: []
});
this.after('initialize', function()
this.templates({
// string literal, used as partial {{> item }}
item: '<li>{{description}} - $<b>{{price}}<\/b><\/li>',
// pre-compiled template loaded externally
main: 'list-component',
// template via <script> tag id selector
list: '#list'
});
this.$node.html(this.render('main', this.attr));
this.$node.append(this.render('list', this.attr));
});
}, withHandlebarsView);
})();
<!-- Attach component to DOM -->
ListComponent.attachTo('#list-component', {
title: 'My List',
items: [
{ description: 'one', price: 10.00 },
{ description: 'two', price: 20.00 }
]
});
</script>
Development of this component requires Bower, and preferably Karma to be globally installed:
npm install -g bower karma
Then install the Node.js and client-side dependencies by running the following commands in the repo's root directory.
npm install
bower install
To continuously run the tests in Chrome and Firefox during development, just run:
karma start
Anyone and everyone is welcome to contribute. Please take a moment to review the guidelines for contributing.