17

I need to use handlebars.js and I also use Blade template engine from Laravel (PHP Framework). The tags {{}} conflict with blade's placeholders that are exactly the same.

How can I change those {{var}} to something like <% var %> ?

ajtrichards
  • 29,723
  • 13
  • 94
  • 101
George D.
  • 1,630
  • 4
  • 23
  • 41
  • 2
    The workaround I did is to regex replace them with JS. I used this code -> var templatecontent = $("#template").html().replace(/<%/, '{{').replace(/%>/, '}}'); var template = Handlebars.compile(templatecontent); – George D. Jan 14 '13 at 19:29
  • 1
    But its a workaround, not sure if its the right thing to do here. – George D. Jan 14 '13 at 19:30

8 Answers8

29

Although it may be true that you can't configure Handlebars' expression delimiters, that's not the only way to resolve the conflict between Handlebars and Blade. Blade provides syntax that allows you to avoid the conflict by designating what should be passed on to Handlebars. (This is fitting, since Blade created the conflict to begin with, and it's necessary, since Blade is processing the template before Handlebars ever sees it.) Just prepend @ before the curly braces that you want Blade to ignore and pass as-is to Handlebars. Here's a very short snippet of a much larger example:

...
    <link
        rel="stylesheet"
        type="text/css"
        href="{{ asset("css/bootstrap.theme.3.0.0.css") }}"
    />
    <title>Laravel 4 Chat</title>
</head>
<body>
    <script type="text/x-handlebars">
        @{{outlet}}
    </script>
...

{{outlet}} will be passed to Handlebars, but {{ asset("css/bootstrap.theme.3.0.0.css") }} will be handled by Blade.

iconoclast
  • 21,213
  • 15
  • 102
  • 138
9

I created handlebars-delimiters on GitHub / npm to make it easy to use custom delims with Handlebars.

var Handlebars = require('handlebars');
var useDelims = require('handlebars-delimiters');

var a = Handlebars.compile('{{ name }}<%= name %>')({name: 'Jon'});
console.log(a);
//=> 'Jon<%= name %>'


// Pass your instance of Handlebars and define custom delimiters
useDelims(Handlebars, ['<%=', '%>']);
var b = Handlebars.compile('{{ name }}<%= name %>')({name: 'Jon'});
console.log(b);
//=> '{{ name }}Jon'

The idea for the compile function came from https://stackoverflow.com/a/19181804/1267639

Suggestions for improvement or pull requests are welcome!

Community
  • 1
  • 1
jonschlinkert
  • 10,872
  • 4
  • 43
  • 50
  • 1
    +1 making real libraries, putting them on GitHub where we can send PRs and file issues, and publishing them on npm rather than having people copy paste the same solutions from StackOverflow. – mikemaccana Sep 02 '15 at 11:02
  • there are 3 principal layers of potential template execution imo. On first execution, essentially on a domain/language, at server delivery (good old CGI time) and in the client. I am using {% {@ and {{ respectively. I am also using {"some text"} as effectively shorthand for {%__ "some text"%}, meaning call the __ helper to translate "some text" at first exec . All of these are facilitated by this. thx – Mark Lester Jul 08 '20 at 17:04
5

I've made this function. Hope it can be useful for someone..

/**
* change the delimiter tags of Handlebars
* @author Francesco Delacqua
* @param string start a single character for the starting delimiter tag
* @param string end a single character for the ending delimiter tag
*/
Handlebars.setDelimiter = function(start,end){
    //save a reference to the original compile function
    if(!Handlebars.original_compile) Handlebars.original_compile = Handlebars.compile;

    Handlebars.compile = function(source){
        var s = "\\"+start,
            e = "\\"+end,
            RE = new RegExp('('+s+'{2,3})(.*?)('+e+'{2,3})','ig');

            replacedSource = source.replace(RE,function(match, startTags, text, endTags, offset, string){
                var startRE = new RegExp(s,'ig'), endRE = new RegExp(e,'ig');

                startTags = startTags.replace(startRE,'\{');
                endTags = endTags.replace(endRE,'\}');

                return startTags+text+endTags;
            });

        return Handlebars.original_compile(replacedSource);
    };
};

//EXAMPLE to change the delimiters to [:
Handlebars.setDelimiter('[',']');
biondo
  • 151
  • 2
  • 3
  • It seems not working with Handlebars v3.0.3. I created a new answer based with your source code, and it works now. Thank you! – Kevin Campion Jul 19 '15 at 15:50
5

Instead of changing the delimiters you can create files with your handlebars templates in without the .blade extension. Just include these files in your blade template. E.g

Blade Template File - template.blade.php

@extends('master.template')

@section('content')

    @include('handlebars-templates/some-template-name') 

@stop

some-template-name File - some-template-name.php

<script type="text/x-handlebars" data-template-name="content">
<div>
 <label>Name:</label>
 {{input type="text" value=name placeholder="Enter your name"}}
</div>
<div class="text">
<h1>My name is {{name}} and I want to learn Ember!</h1>
</div>
</script>
ajtrichards
  • 29,723
  • 13
  • 94
  • 101
4

This is not possible with "standard" Handlebars. https://github.com/wycats/handlebars.js/issues/227

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • hm...ok. How to bypass it then? Something like my comment? – George D. Jan 14 '13 at 19:31
  • 2
    Sure, or store the templates outside of the HTML entirely, as suggested on GH: https://github.com/wycats/handlebars.js/issues/227#issuecomment-9950931 – Matt Ball Jan 14 '13 at 19:32
3

"If you need to display a string that is wrapped in curly braces, you may escape the Blade behavior by prefixing your text with an @ symbol"

@{{varname}}

Hope it helps!

Jonas
  • 588
  • 2
  • 10
  • 23
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Ander Biguri Oct 07 '14 at 11:49
  • @AnderBiguri: how is this a link? ;-) – Stefan Oct 07 '14 at 11:51
  • @Stefan Sorry, it gets "autowritteng" while moderating. The point is, there is no explanation in this answer. Just gives an answer, but not explaining why or why not. – Ander Biguri Oct 07 '14 at 11:53
  • @AnderBiguri: agreed. – Stefan Oct 07 '14 at 11:54
0

I used and updated the source code of user1875109 and now it works with Handlebars v3.0.3:

/**
* change the delimiter tags of Handlebars
* @author Francesco Delacqua
* @param string start a single character for the starting delimiter tag
* @param string end a single character for the ending delimiter tag
*/
Handlebars.setDelimiter = function(start,end){
    //save a reference to the original compile function
    if(!Handlebars.original_compile) Handlebars.original_compile = Handlebars.compile;

    Handlebars.compile = function(source){
        var s = "\\"+start,
            e = "\\"+end,
            RE = new RegExp('('+s+')(.*?)('+e+')','ig');

            replacedSource = source.replace(RE,function(match, startTags, text, endTags, offset, string){
                var startRE = new RegExp(s,'ig'), endRE = new RegExp(e,'ig');

                startTags = startTags.replace(startRE,'\{');
                endTags = endTags.replace(endRE,'\}');

                return startTags+text+endTags;
            });

        return Handlebars.original_compile(replacedSource);
    };
};

//EXAMPLE to change the delimiters to [:
Handlebars.setDelimiter('[',']');
Kevin Campion
  • 2,223
  • 2
  • 23
  • 29
-1

There is an option to tell template engine for not parsing certain part of code and treat it as plain text.

Find the following ways to do it, hope it helps somebody.

In blade template engine (laravel) you can use @verbatim Directive. So that you dont have to add @ to every variable. Example :

@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim

Similarly for twig template engine (symfony) you can block the whole code by using

{% verbatim %}
    <div>
        My name is {{name}}. I am a {{occupation}}.
    </div>
{% endverbatim %} 
maxwells
  • 539
  • 4
  • 15