Trying out backbone+express with Jade as default templating.
Following a tutorial here(Great tutorial)
Confusion:
Many tutorials about backbone uses underscore template or handlebar to compile and render view.
I was using Jade as default template engine. My question is if I am using Jade then do I have to use another templating like Handlebar or underscore. If not how can I achieve following in Jade
render: function() {
var template = $("#booktemplate").html();
var compiled = Handlebars.compile(template);
var html = compiled(this.model.attributes);
this.$el.html(html);
return this;
},
My assumption: I am thinking Jade and Handle bar both are templating system and can be used alternatively. Is it so?
Why not use both Jade & Handlebar? I dont want to use two different syntaxes
#{} from jade / {{}} from Handlebar
Using Jade on the browser is not really a simple task. Thing is Jade is built for server side and does not support browsers.
This is why you'll often see people using two templates engines (if they use Jade). Some others are just gonna use Handlebars or Underscore everywhere - this is easier because templates engine working in the browser should work on the server. The other way around is not always true though.
Point to be taken here is that before starting to use a template engine, make sure it supports the environment you wish to target. There's plenty of options in term of engine, and this site can help you find one fittings your need: http://garann.github.io/template-chooser/
If you're really like Jade, then, you can use a stack like Browserify and some middleware (Jadeify) to make it work after pre-compilation. But you need to buy into the browserify concept and accept to precompile everything, everytime. You can check this related question for more details: https://stackoverflow.com/a/6623561/1024223
Related
Background
I am currently building a website that uses NodeJS for the server, Express Handlebars(Just Handlebars but server side) , and hopefully AngularJS for some client side stuff.
The Problem
AngularJS and Handlebars use the same syntax for templating
{{foo}}
This causes a problem where AngularJS code will be interpreted by Express Handlebars first, which will then throw an error because the data it is trying to pull only exists in Angular not Node.
The Question
Is there a way to get AngularJS and Express Handlebars to work together?
Possible Solutions
Change the syntax of AngularJS
I was looking at BackboneJS and it looks like it is possible to change the syntax. There could possibly be something similar is AngularJS.
Create a ng helper in Express Handlebars.
It would just return its un-parsed content. However I couldn't figure out how to do this.
Your first solution is possible, AngularJS allow to change the start/end symbols of text interpolation like this:
appModule.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
});
Then you could use it in your template:
<div>{[{message}]}</div>
Also see: $interpolateProvider documentation
Hope this helps.
You can always use the ng-bind syntax instead:
<p ng-bind="user.profile.description"></p>
This is identical to
<p>{{user.profile.description}}</p>
From the Angular docs for ngBind:
Typically, you don't use ngBind directly, but instead you use the double curly markup like {{ expression }} which is similar but less verbose.
It is preferable to use ngBind instead of {{ expression }} if a template is momentarily displayed by the browser in its raw state before Angular compiles it. Since ngBind is an element attribute, it makes the bindings invisible to the user while the page is loading.
In order to maintain the AngularJS Style, your second solution is better, Create a helper in Express Handlebars.
References to the Handlebars Web Site: http://handlebarsjs.com/block_helpers.html, you can register a helper raw-helper
Handlebars.registerHelper('raw-helper', function(options) {
return options.fn();
});
and use it in your hbs template by putting it in a quadruple-stash {{{{
{{{{raw-helper}}}}
<div class="container" ng-controller="AppCtrl">
Total Members: {{members.length}}
</div>
{{{{/raw-helper}}}}
There is a better way: \{{foo}}.
Handlebars content may be escaped in one of two ways, inline escapes or raw block helpers. Inline escapes created by prefixing a mustache block with \ . Raw blocks are created using {{{{ mustache braces. You can see this http://handlebarsjs.com/expressions.html#helpers
I would recommend using the AngularJS's data-binding syntax (what looks similar to Handlebars) and have your NodeJS server simply serve the static AngularJS source code. I prefer to offload the templating onto the client and therefore put less stress on your server, not to mention that AngularJS and other MVC frameworks (my favourite is EmberJS) are great for dynamically building the webpage.
I am a fan of Yeoman and here is a generator for building an Angular project served by NodeJS: https://github.com/yeoman/generator-angular
I'm using underscore template engine for an backbone application. As of now I have over 15 templates in the <head>. Its getting hard to maintain. So far, most of the solutions I seen to manage templates ended up needing them to be js files. That's also a headache, I prefer them to be html files for editing purposes.
I took a look at requirejs and not sure if I need that since it kinda revolves around a more modular approach that I can't say I'm using at the moment (although I will soon).
What will be the best way to manage templates and load/cache them as needed?
Personally we needed a robust solution at my company, so we went with:
Require.js - for module loading
Handlebars - for more powerful templating than Underscore can offer
HBS - an excellent require plug-in from Alex Sexton that handles bringing compiled templates in via Require
With this setup I can keep all of my templates in their own file, and then to use them I have files like this:
define(['template!path/to/someTemplate'], function(someTemplate) {
var MyNewView = BaseView.extend({template: someTemplate});
$('body').append(new MyNewView().render().el);
}
(and as you might guess we have a base Backbone view called BaseView which uses the view's template property to render the view).
Now, all that being said, if you don't need such a robust setup then Require may not be for you. In that case I would do the following:
Put all of your templates in to one or more HTML files; wrap them in script tags, like so:
<script id="dummyTemplate" type='text/template'>
<span>I'm a template!</span>
</script>
Write some code on your server-side to include those HTML files in the main HTML file you send to the client
Write a function which takes a template ID, gets the text of that element, compiles it in to a template, and returns that template (maybe cache the compiled templates if you want ... of course, with Underscore templates I don't think you even need compiling, so you can skip all that).
Use your function to access your templates: $("#something").html(templateFunc('dummyTemplate').template())
This will allow you to store your templates in html files (for syntax coloring), but still access them conveniently in JS. You can also divide your templates between as many files as you want, as long as you can write include logic to bring them in.
If you do opt for Require though, definitely check out the HBS plugin. And if you haven't looked at Handlebars templates yet, you might want to; they're far more powerful than Underscore ones (but like any good templating system, don't allow for too much logic).
Not sure what you mean by it being unmaintainable. Is it just a long list?
You don't need to keep your templates in the head. They can be at the bottom of your body as well. They just need to be defined before you try to use them.
One thing you might look into, depending on the server technology you are using would be to separate your templates into a different HTML file and include it at runtime.
I have a rather robust project that has all of its templates implemented in Slim and a little Haml. I'm considering moving the project over to a Node.js based structure (probably built atop Tower.js or something similar; maybe Meteor), however I would like to continue using Slim or Haml for the templates rather than shifting over to another template engine.
Has anyone done this or spent the time to figure out how to accomplish this so far, and if so, what were your findings?
Tower.js wraps the express.js template engine system, so you should be able to use any express.js template engine by adding the following to the configuration Tower.View.engine = "haml"
Tower.js uses mint, which has HAML built in, so you just need the haml module in your directory.
Slim is problematic though. First its not within mint.js directly, so you'll need to register a new template engine. Todo that you'll need to
create a function customAdapter that mint.js can use, you can look at the mint.js sourcecode. Heres an example of the haml adapter function:
function(content, options, callback) {
var result;
result = require('hamljs').render(content, options || {});
if (callback) {
callback.call(this, null, result);
}
return result;
}
you'll need to add the adapter to mint.js by doing require("mint").engines.slim = customAdapter
But there's no express.js engine for Slim, and since Slim contains ruby code snippets, it isn't likely there will be.
If you really want to do it so you'll need to create your own javascript parser for the template files (probably using something like http://opalrb.org/ , though with no specific ruby libraries), and then create an express.js engine (which I don't know how to).
I doubt it will be a very fruitful exercise.
I suggest you either convert your Slim files to haml (or jade, or any template engine that can be used by express.js) or don't make the move.
I could also not find any way to automatically convert Slim to haml or any other template engine (probably due to the fact that it contains ruby code), so you will have to do the conversion entirely manually.
i'm very new to Handlebar js. In every article about the HandleBar js there is a word called (mustache js). So,
1. What is the relation between Handllebar js and Mustache js?
2. Is it necessary to read mustache js before handlebar js?
3. What s advantage of HandleBar js over Mustache js?
Thanks.
Handlebars.js is a superset of Mustache.js. It offers all the same ability to insert JSON into templates plus additional abilities to do some basic if/then, etc. In general, I find it much easier to do templating with Handlebars.
Mustache is very much about not having any logic in your template at all. Every piece that gets inserted into it should be pre-chewed so there's no need for any logic. I find that to not at all be realistic.
Just realized that I didn't answer one of your questions. No, it is not necessary to read about Mustache before using Handlebars. The Handlebars documentation is sufficient on its own.
P.S. One of our favorite Handlebars features is "helpers" which allow you to create new keywords in the language for specific things (for example, we use one to format numbers and sometimes replace them with "N/A" for zero values).
P.P.S. A great way to try out Handlebars and see some templates in action (and also to play with your own templates and JSON) is http://www.tryhandlebarsjs.com/
According to this website (which also provides a benchmark between the two)
handlebars.js is a compiled mustache implementation with some additional
features
I set up a node.couchapp.js CouchApp and pushed it to my CouchDB. There is Sammy and jQuery included by default. Now, I'd like to add Mustache for templates, but don't exactly know where? I could use it as Node.js module or jQuery plugin.
I started with some sample code, just to see if it works, but it doesn't:
ddoc.lists = {
"basic": "function (head, req) { var that = this; provides('html', function () { var to_html = require('modules/mustache').to_html; var members = []; var row; while (row = getRow()) { members.push({club: row.key[0], name: row.key[1]}); } return to_html(that.templates['roster.mustache'], { members: members }); }) }"
};
Results in:
{"error":"invalid_require_path","reason":"Object has no property \"modules\". ...
Project structure is:
. Project
| - app.js
| - attachments
| - - scripts
| ` - index.html
| - modules
| | mustache
| - ` - mustache.js
` - templates
Update
I modified the code a bit and excluded the template folder as possible cause. This snippet is from a solved question here on SO, so it should actually work. But it's still the same error. I installed mustache.js with npm install mustache and renamed the folder from node_modules to modules (didn't work with node_modules either).
"basic": "function (head, req) { provides('html', function () { var template = '{{%IMPLICIT-ITERATOR}}{{name}}: <ul> {{#items}}<li>{{.}}</li>{{/items}} </ul>'; var mustache = require('./modules/mustache/mustache.js'); return mustache.to_html(template,view);});}"
But it's still the same error.
I'm not sure about the specific error you're getting, but to your question:
"Now, I'd like to add Mustache for templates, but don't exactly know where? I could use it as Node.js module or jQuery plugin."
You can use it in both.
As Node.js runs on the server-side this effectively gives you a way to define your template once (using Mustache in this case) and run it both server-side (using Node.js) and client-side (using the jquery-plugin).
Just for the overview (you may well already know this):
Imagine rendering a search-result of products:
The traditional way is to render the products with some server-side templating engine.
Now, let's say you want to enable filtering / sorting of the search-results. Generally speaking you have 3 options:
do a normal (non-ajax call) to the server, do server-side templating and spit out the new page
do an ajax-call to the server, do server-side templating and spit out html, pick it up client-side and insert it into a dom-element.
do an ajax-call to the server, generate a json-object, which you render client-side using a client-side templating engine (such as Mustache) into a dom-element.
Option 3 is arguably the best solution from a usability standpoint. (quick, low-bandwidth, no page flickering or page jumping, etc. ) . However think about a fallback/non-js way for SEO if you need it.
When implementing option 3 however you now have the situation of needing a server-side templating language to render products on the initial page load, and a client-side templating language to render products returned from subsequent ajax-calls. Both result in the exact same html. Not very DRY.
Here node.js comes into play, which eliminates the need for writing a seperate server-side template. Instead, just let node.js spit out the initial page using the exact same mustache template you use on the client-side.
Of course you could go the only client-side route: spitting out json on the intial page load as well, and render that on the client. This of course if terrible from a seo-standpoint. Some apps don't the search engine indexing however, in which case the 'everything on the client' approach is a good alternative.
Some related questions:
Client-side templating language with java compiler as well (DRY templating)
Good DRY approach to rendering and AJAX updating of page