How to use Angular.js and Twig without the conflict of double curly braces

How to use Angular.js and Twig without the conflict of double curly braces

Twig and Angular.js use the same symbols to control its rendering structure : {{ and }} , which isn't good for those ones that uses Twig as default backend template engine.

Although, there may are developers that doesn't has this problem and they'll be thinking : Why use a backend rendering template if you're supposed to do that with angular and why this problem happens?

The problem by itself is that a Twig variable or instruction to be printed will be always processed and there are not {{ or }} without being processed by Twig, and that's basically when the errors appear due to angular. If you start to write only angular in a Twig file:

<body ng-app="myApp" ng-controller="myCtrl">
{#
Note that {{x}} is not Twig but AngularJS
#}
<h1>{{label}}</h1>

<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
    $scope.label = "Hello world";
});
</script>
</body>

Twig will parse those symbols not as angular (plain html) but as Twig, therefore the error message is that label variable doesn't exists.

Fortunately, there many ways to solve this issue.

Possible solutions with Twig

The most reliable way to solve this issue, is to making by the Twig Way as there are many options that you can use.

Change the rendering symbols

Twig allows some syntax customization for the block delimiters. It's not recommended to use this feature as templates will be tied with your custom syntax. But for specific projects, it can make sense to change the defaults. To change the block delimiters, you need to create your own lexer object:

<?php

$twig = new Twig_Environment();

$lexer = new Twig_Lexer($twig, array(
    'tag_comment'   => array('[#', '#]'),
    'tag_block'     => array('[%', '%]'),
    'tag_variable'  => array('[[', ']]'),
    'interpolation' => array('#[', ']'),
));
$twig->setLexer($lexer);

However, if you change the lexer delimiters ({{ and }}) is not recommended because changing them would forbid you to use any templates provided by shared bundles (including the exception templates provided by TwigBundle itself) and third party Twig libraries. Read more about the Lexer here.

Prevent twig from processing a block

The verbatim tag marks sections as being raw text that should not be parsed. This tag comes in handy as you don't need to modify your angular work style i.e :

<body ng-app="myApp" ng-controller="myCtrl">

{#
  If you don't use verbatim in the following line
  Twig will crash as "x" doesn't exists.
  To solve it wrap in a verbatim tag.
#}

{% verbatim %}
<h1 ng-repeat="x in records">{{x}}</h1>
{% endverbatim %}

<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
    $scope.records = [
        "Alfreds Futterkiste",
        "Berglunds snabbköp",
        "Centro comercial Moctezuma",
        "Ernst Handel",
    ]
});
</script>

</body>

Note: in older versions of twig this tag is named raw but was renamed to avoid confusion with the raw filter.

You can see the verbatim tag working in the following twig fiddle :

Write your angular template as a string

Simply enclose your Angular template inside a Twig string.

<h1 ng-repeat="x in records">{{'{{x}}'}}</h1>
{#
    The output will be :
    <h1 ng-repeat="x in records">{{x}}</h1>
#}

{# Or mix with twig variables #}

{%set aTwigVariable = "x" %}
<h1 ng-repeat="x in records">{{'{{' ~ aTwigVariable ~ '}}'}}</h1>
{#
    The output will be :
    <h1 ng-repeat="x in records">{{x}}</h1>
#}

Although it modifies the way you code , this solution is very simple, but functional.

Warning: you should use single quotes, not double quotes. Double quotes enable string interpolation of Twig so you have to be more careful with the contents, especially if you are using expressions.

Create a Twig function that appends the symbols automatically

Instead of write the curly braces by yourself, create a Twig function that does it for you, of this way the curly braces will be not processed for Twig.

According to the way you're using Twig you may want to read the Symfony documentation or the official Twig docs.

Basically the function would look like :

<?php 
public function angularParse($string = ""){
    return "{{".$string."}}";
}

And register it  in your extension class:

<?php 
public function getFunctions()
{
    return array(
        new \Twig_SimpleFunction('angularParse', array($this, 'angularParse')),
    );
}

Note: obviously can't be more simple. You can add more things as replace the symbols if they've already been appended.

Finally use it in twig :

<h1 ng-repeat="x in records">{{angularParse('x')}}</h1>
{#
    The output will be :
    <h1 ng-repeat="x in records">{{x}}</h1>
#}

Possible solutions with Angular

In opposite of twig, angular doesn't has more than 1 option to solve your issue.

Change the rendering symbols

Angular allow you to change the way you render angular variables in the view changing the interpolation provider.

Although this feature is sometimes used to mix different markup languages, e.g. to wrap an Angular template within a Python Jinja template (or any other template language as Twig). Mixing templating languages is very dangerous. The embedding template language will not safely escape Angular expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS) security bugs.

To change the interpolation providers, use the following snippet :

angular.module('myApp', []).config(function($interpolateProvider){
    $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
});

Read more about the interpolateProvider in the documentation of Angular here.

If you know another way to use Angular and Twig at time, please share it with the community in the comment box.

Have fun

This could interest you

Become a more social person