36

I'm trying to template a template, like below:

{{{
{
  "name" : "{{name}}",
  "description" : "{{description}}"
}
}}}

{{{debug this}}}

<h1>{{name}}</h1>

Where I want to triple brackets to stay, but double brackets to be replaced with the JSON passed in. Anyone know the best way to do this without writing post-process JS code, and if not, is there a good nodeJS template engine for this type of scenario?

m59
  • 43,214
  • 14
  • 119
  • 136
Nick Jonas
  • 1,197
  • 4
  • 13
  • 24
  • Is there a good reason you're doing this? It seems a bit complicated! Maybe you can achieve it some other way? – Jamund Ferguson Dec 19 '12 at 04:06
  • 1
    I am creating a CLI build/scaffold generator for a javascript framework, so I'd like templates to be a part of that... – Nick Jonas Dec 19 '12 at 07:25
  • 1
    Have you looked at the [grunt init](https://github.com/gruntjs/grunt-init) templating system that helps in creating templates like this? . [Yeoman](http://yeoman.io) is also doing something similar. Hopefully it will take some of the pain out of building an generator like this. As far as handlebars, it doesn't look like there is a way to change delimiters, but there is an escape option built in according to this issue https://github.com/wycats/handlebars.js/issues/146. Many other systems (mustache, underscore, etc) allow for changing delimeters. – Jamund Ferguson Dec 25 '12 at 21:49

7 Answers7

77

As described in this Question handlebars doesn't support changing the delimiters. But you can escape the double braces with a backslash like this:

HTML:

... \{{ myHandlbarsVar }} ...
Community
  • 1
  • 1
tmuecksch
  • 6,222
  • 6
  • 40
  • 61
  • 20
    This doesn't work in Mustache . . . and this question is specifically about mustache. Clearly, people have found this answer useful, so no downvote from me, but wanted to comment for anyone who found this and thought it might solve all their problems. – tandrewnichols Oct 26 '15 at 20:41
  • 1
    worked for me in handlebars, I can even do stuff like `\{{ unrendered {{ data }} }}` – Guido Tarsia Mar 22 '17 at 17:50
  • 2
    2021 and this answer is still saving people(like me), thanks a lot! Handlebars documentation link: https://handlebarsjs.com/guide/expressions.html#escaping-handlebars-expressions – Nevitones Jan 07 '21 at 18:17
56

You can switch delimiters to something that won't conflict with the triple mustaches, like erb-style tags:

{{=<% %>=}}
{{{
{
  "name": "<% name %>",
  "description": "<% description %>"
}
}}}
{{{debug this}}}
<%={{ }}=%>

Note that you can do this as many times as you like throughout your template. Any time you run into something that conflicts, pick a new set of delimiters :)

bobthecow
  • 5,047
  • 25
  • 27
14

You can also assign Mustache.tags = ["[[", "]]"]; before your template compilation.

http://jsfiddle.net/fhwe4o8k/1/

e.g.

    $(function () {
        Mustache.tags = ["[[", "]]"];
        var template = $('#test').html();
        Mustache.parse(template);
        var rendered = Mustache.render(template, {test: "Chris"});
        $('#content-placeholder').html(rendered);
    });
Christopher Marshall
  • 10,678
  • 10
  • 55
  • 94
8

another option is create a helper for outputing curly brackets.

Handlebars.registerHelper('curly', function(object, open) {
    return open ? '{' : '}';
});

and then use it in the template like this:

<script id="template" type="text/x-handlebars-template">
    {{curly true}}{{name}}{{curly}}
</script>

which then outputs:

{Stack Over Flow Rocks}
Austin Haws
  • 364
  • 2
  • 6
  • 15
0

The template contains HTML, so you could use HTML-Entities, for example the ASCII-codes 123 and 125 for braces: &#123;{{myValue}}&#125;

mev
  • 1
-1

I just wanted slightly different approach. I have tried few other other ways and here are few things which I didn't like about them:

  1. Changing Angular default {{obj.property}} brackets to something else is a bad idea. Mainly beacause as soon as you start using third party components which are not aware of you non standard angular configuration, bindings in those third part components will stop working. Also worth mentioning that AngularJS team doesn't seem to want to go the route of allowing multiple binding notations, check this issue
  2. I quite like Mustache templates and don't want to switch the whole project to something else because of this small issue.
  3. Quite a few people recommend not to mix client and server side rendering. I don't fully agree, I believe if you are building a multipage website which has few pages with angular and some other which are static (something like about us or Terms and Conditions pages) it is perfectly fine to use server side templating to make maintaining those pages easier. But that said, for parts which are Angular you shouldn't mixing server side rendering.

Ok no my answer: If you are using NodeJS and Express you should be to the following:

Replace bindings {{}} in your angular part with something like {[{}]} (or something completely unique)

Now in you route add a callback to you render method:

app.get('/', function(req, res){
  res.render('home', {
    title: 'Awesome Website',
    description: 'Uber Awesome Website'
  }, function(err, html){
    var htmlWithReplacedLeftBracket = html.replace(/{\[{/g, '{{');
    var finalHtml = htmlWithReplacedLeftBracket.replace(/}\]}/g, '}}');
    res.send(finalHtml);
  });
});

This should allow you to use Mustache together with AngularJS. One improvement you could do is extract that method into a separate module to reuse across all routes.

Vitalij
  • 4,587
  • 9
  • 42
  • 65
-6

This is a good solution I have found for this type of problem where you can easily switch delimiters in the template settings in runtime:

http://olado.github.com/doT/

You can do the RegEx settings like this:

doT.templateSettings = {
  evaluate:    /\{\{([\s\S]+?)\}\}/g,
  interpolate: /\{\{=([\s\S]+?)\}\}/g,
  encode:      /\{\{!([\s\S]+?)\}\}/g,
  use:         /\{\{#([\s\S]+?)\}\}/g,
  define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
  conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
  iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
  varname: 'it',
  strip: true,
  append: true,
  selfcontained: false
};
Nick Jonas
  • 1,197
  • 4
  • 13
  • 24
  • 2
    You've got to be kidding. You accept your own answer that does not answer your own question which is perfectly addressed by @bobthecow? – Arnaud Meuret Jul 24 '14 at 10:57