308

I want to use AngularJS with Django however they both use {{ }} as their template tags. Is there an easy way to change one of the two to use some other custom templating tag?

Dominic Mitchell
  • 11,861
  • 4
  • 29
  • 30
Endophage
  • 21,038
  • 13
  • 59
  • 90
  • 1
    I only render one template from django `templates` directory, the rest I put in `static`. That way you don't have interference. There's a tutorial I wrote here: https://coderwall.com/p/bzjuka/set-up-drf-to-play-well-with-angular-templates?p=1&q= – Connor Leech May 26 '15 at 21:21
  • how to pass the data between angular2 and jinja2 ? Any help – Narendra Oct 30 '17 at 18:29
  • @Narendra that's a different problem not relevant to this question. Please search for it and if you don't find an answer, ask it as a new question. – Endophage Nov 07 '17 at 06:03

12 Answers12

303

For Angular 1.0 you should use the $interpolateProvider apis to configure the interpolation symbols: http://docs.angularjs.org/api/ng.$interpolateProvider.

Something like this should do the trick:

myModule.config(function($interpolateProvider) {
  $interpolateProvider.startSymbol('{[{');
  $interpolateProvider.endSymbol('}]}');
});

Keep in mind two things:

  • mixing server-side and client-side templates is rarely a good idea and should be used with caution. The main issues are: maintainability (hard to read) and security (double interpolation could expose a new security vector - e.g. while escaping of serverside and clientside templating by themselves might be secure, their combination might not be).
  • if you start using third-party directives (components) that use {{ }} in their templates then your configuration will break them. (fix pending)

While there is nothing we can do about the first issue, except for warning people, we do need to address the second issue.

Joseph Silber
  • 214,931
  • 59
  • 362
  • 292
Igor Minar
  • 9,574
  • 3
  • 22
  • 13
  • Bootstrapping templates with data is not an uncommon practice. It's actually recommended in backbone.js – Endophage Jun 20 '12 at 06:30
  • 4
    Would you mind explaining your first point (maintenance, security, and other concerns for mixing server-side and client-side templates)? A little more explanation would be helpful. – Brian Jul 03 '12 at 19:09
  • @Endophage - injection of data along with dynamic versioning of asset urls are among few legitimate exceptions. – Igor Minar Aug 11 '12 at 07:23
  • 1
    @btlachance - I expanded the answer. – Igor Minar Aug 11 '12 at 07:23
  • How exactly to implement this custom delimiter, im having problem to implement in my application. Nothing happen. – Azri Jamil Oct 16 '12 at 20:52
  • 13
    Since $interpolateProvider returns self when used as a setter, here's a slightly more compact version: `$interpolateProvider.startSymbol('{[{').endSymbol('}]}');` – Mark Rajcok Oct 20 '12 at 16:48
  • 5
    Looks like the "fix" is closed. Does that mean that isn't now safe to use third-party components? – Alex Okrushko Dec 09 '12 at 23:37
  • @IgorMinar: following a chain of links to another issue and then a problem report, https://github.com/IgorMinar/angular.js/commit/bf669dea0220ebc39e69bd375665fea67bb3c21f - seems like the "fix" was implemented in your fork, but perhaps has not made it to the mainline AngularJS code. Is that right? – RichVel Apr 25 '13 at 09:30
  • 1
    any way to also update the $interpolateProvider for raw output? e.g. {{{foo}}} becoming {{[{foo}]}} ? – tester Aug 26 '13 at 07:05
  • If it's helpful to others, our team prefers `<<` and `>>`, as in `$interpolateProvider.startSymbol('<<').endSymbol('>>');` – rattray Mar 27 '14 at 18:42
  • @'alex okrushko' no, it doesn't seem safe (with angular 1.3). My variables show correctly and it feels awesome, but my angular-ui calendar won't display anything. I'd love to be proven I'm wrong. – Ehvince Dec 10 '15 at 22:46
  • @MarkRajcok I have tried your method. But it's not working for me.. At present `verbatim` alone works.. – Avinash Raj Dec 30 '15 at 12:52
  • If one writes SPA with pure AJAX backend, then having only client-side templates not mixed with server-side templates is OK. But there are many applications when non-SPA usage is required. So it was really strange choice to chose {{}} for AngularJS templates, knowing that most of server-side templates already use the conflicting syntax. Luckily I use Knockout.js which does not clash with server-side templates. But too bad it is much much less popular than Angular - much harted to find related job offers. – Dmitriy Sintsov Jul 21 '16 at 13:38
126

you can maybe try verbatim Django template tag and use it like this :

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>

{% verbatim %}
<div ng-app="">
    <p>10 is {{ 5 + 5 }}</p>
</div>
{% endverbatim %}
texnic
  • 3,959
  • 4
  • 42
  • 75
Bessoufi Mounir
  • 1,368
  • 1
  • 8
  • 7
  • While that's a very valid solution, there are cases where I want to be able to bootstrap my views with data from the server so this would get messy fast. Think things like the user's username, it's not going to change so I'll just write it into the template at the server but there may be pieces around it that I'll write in with angular. – Endophage May 30 '12 at 17:36
  • 16
    Verbatim is part of Django core tags since version 1.5: https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#verbatim – Pratyush Feb 12 '13 at 07:27
  • 11
    In Django 1.7 you don't need to load verbatim since it's in the standard tag library. You only need to use the tags themselves. – highpost Oct 22 '14 at 05:41
  • 1
    Would be nice to have a way to change Django default brackets from settings, but this works too. – Adrian Lopez Oct 28 '14 at 17:34
  • To get values from Django context into javascript, you should use the `json_script` built in template tag. This creates a `` tag with a given ID that you can then load in your javascript with no vectors for injection. – Adam Barnes Aug 20 '21 at 13:13
43

If you did separate sections of page properly then you can easily use angularjs tags in "raw" tag scope.

In jinja2

{% raw %}
    // here you can write angularjs template tags.
{% endraw %}

In Django template (above 1.5)

{% verbatim %}    
    // here you can write angularjs template tags.
{% endverbatim %}
Wooble
  • 87,717
  • 12
  • 108
  • 131
thanksnote
  • 1,012
  • 11
  • 9
31

We created a very simple filter in Django 'ng' that makes it easy to mix the two:

foo.html:

...
<div>
  {{ django_context_var }}
  {{ 'angularScopeVar' | ng }}
  {{ 'angularScopeFunction()' | ng }}
</div>
...

The ng filter looks like this:

from django import template
from django.utils import safestring

register = template.Library()


@register.filter(name='ng')
def Angularify(value):
  return safestring.mark_safe('{{%s}}' % value)
Wes Alvaro
  • 515
  • 4
  • 7
27

So I got some great help in the Angular IRC channel today. It turns out you can change Angular's template tags very easily. The necessary snippets below should be included after your angular include (the given example appears on their mailing lists and would use (()) as the new template tags, substitute for your own):

angular.markup('(())', function(text, textNode, parentElement){
  if (parentElement[0].nodeName.toLowerCase() == 'script') return;
  text = text.replace(/\(\(/g,'{{').replace(/\)\)/g, '}}');
  textNode.text(text);
  return angular.markup('{{}}').call(this, text, textNode, parentElement);
});

angular.attrMarkup('(())', function(value, name, element){
    value = value.replace(/\(\(/g,'{{').replace(/\)\)/, '}}');
    element[0].setAttribute(name, value);
    return angular.attrMarkup('{{}}').call(this, value, name, element);
});

Also, I was pointed to an upcoming enhancement that will expose startSymbol and endSymbol properties that can be set to whatever tags you desire.

Endophage
  • 21,038
  • 13
  • 59
  • 90
  • 17
    and this is how you do it in angularjs 1.0:var m = angular.module('myApp', []); m.config(function($interpolateProvider) { $interpolateProvider.startSymbol('(('); $interpolateProvider.endSymbol('))'); }); – idursun Mar 19 '12 at 13:45
  • Angular IRC channel. fwiw to whoever, I found one at #angularjs – Shanimal Oct 10 '12 at 20:01
18

I vote against using double parentheses (()) as template tag. It may work well as long as no function call is involved but when tried the following

ng:disabled=(($invalidWidgets.visible()))

with Firefox (10.0.2) on Mac I got a terribly long error instead of the intended logic. <[]> went well for me, at least up until now.

Edit 2012-03-29: Please note that $invalidWidgets is deprecated. However I'd still use another wrapper than double braces. For any angular version higher than 0.10.7 (I guess) you could change the wrapper a lot easier in your app / module definition:

angular.module('YourAppName', [], function ($interpolateProvider) {
    $interpolateProvider.startSymbol('<[');
    $interpolateProvider.endSymbol(']>');
}); 

API docs.

RichVel
  • 7,030
  • 6
  • 32
  • 48
Lukas Bünger
  • 181
  • 1
  • 3
  • Fair point. I hadn't thought of that but I wasn't particularly advocating using `(())`, I just wanted to be able to configure the delimiters. – Endophage Mar 07 '12 at 22:10
17

You could always use ng-bind instead of {{ }} http://docs.angularjs.org/api/ng/directive/ngBind

<span ng-bind="name"></span>
Indomitable
  • 808
  • 9
  • 9
16

I found the code below helpful. I found the code here: http://djangosnippets.org/snippets/2787/

"""
filename: angularjs.py

Usage:
    {% ng Some.angular.scope.content %}

e.g.
    {% load angularjs %}
    <div ng-init="yourName = 'foobar'">
        <p>{% ng yourName %}</p>
    </div>
"""

from django import template

register = template.Library()

class AngularJS(template.Node):
    def __init__(self, bits):
        self.ng = bits

    def render(self, ctx):
        return "{{%s}}" % " ".join(self.ng[1:])

def do_angular(parser, token):
    bits = token.split_contents()
    return AngularJS(bits)

register.tag('ng', do_angular)
furins
  • 4,979
  • 1
  • 39
  • 57
nu everest
  • 9,589
  • 12
  • 71
  • 90
  • I did use this custom tag but then if I use something like: `

    {% ng location %}

    ` it gets rendered as `{{location}}` - yes with curly braces! It doesn't render the value of $scope.location which is hardcoded in my controller. Any idea what am I missing?
    – Keshav Agrawal May 11 '14 at 10:14
12

If you use django 1.5 and newer use:

  {% verbatim %}
    {{if dying}}Still alive.{{/if}}
  {% endverbatim %}

If you are stuck with django 1.2 on appengine extend the django syntax with the verbatim template command like this ...

from django import template

register = template.Library()

class VerbatimNode(template.Node):

    def __init__(self, text):
        self.text = text

    def render(self, context):
        return self.text

@register.tag
def verbatim(parser, token):
    text = []
    while 1:
        token = parser.tokens.pop(0)
        if token.contents == 'endverbatim':
            break
        if token.token_type == template.TOKEN_VAR:
            text.append('{{')
        elif token.token_type == template.TOKEN_BLOCK:
            text.append('{%')
        text.append(token.contents)
        if token.token_type == template.TOKEN_VAR:
            text.append('}}')
        elif token.token_type == template.TOKEN_BLOCK:
            text.append('%}')
    return VerbatimNode(''.join(text))

In your file use:

from google.appengine.ext.webapp import template
template.register_template_library('utilities.verbatim_template_tag')

Source: http://bamboobig.blogspot.co.at/2011/09/notebook-using-jquery-templates-in.html

cat
  • 2,871
  • 1
  • 23
  • 28
  • Thanks ... finally got this working but I had to ... 1) create a new Python module. I named it utilties and put the file verbatim_templatetag.py in it. (The file above with VerbatimNode class defined in it). 2) Change the import statement from: `from django import template` to: `from google.appengine._internal.django import template` Then, in my main file, just changed the filename: `template.register_template_library('utilities.verbatim_template_tag')` – Roger Apr 22 '16 at 10:14
7

You can tell Django to output {{ and }}, as well as other reserved template strings by using the {% templatetag %} tag.

For instance, using {% templatetag openvariable %} would output {{.

Thomas Orozco
  • 53,284
  • 11
  • 113
  • 116
  • 3
    I know that's possible but it's messy... It would be much cleaner (and doesn't seem too big an ask) for the template tag to simply be configurable in one of the frameworks. At the end of the day it's just doing string matching behind the scenes... – Endophage Nov 29 '11 at 02:52
3

I would stick with a solution that uses both django tags {{}} as well angularjs {{}} with a either a verbatim section or templatetag.

That is simply because you can change the way angularjs works (as mentioned) via the $interpolateProvider.startSymbol $interpolateProvider.endSymbol but if you start to use other angularjs components like the ui-bootstrap you will find that some of the templates are ALREADY built with standard angularjs tags {{ }}.

For example look at https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html.

silviud
  • 1,015
  • 1
  • 12
  • 21
  • Good point. There is now a django-angular package in PyPI that's meant to make the two play nice together, but I haven't looked into how much it alleviates the template tag issue. – Endophage Jun 29 '13 at 22:18
0

If you do any server-side interpolation, the only correct way to do this is with <>

$interpolateProvider.startSymbol('<{').endSymbol('}>');

Anything else is an XSS vector.

This is because any Angular delimiters which are not escaped by Django can be entered by the user into the interpolated string; if someone sets their username as "{{evil_code}}", Angular will happily run it. If you use a character than Django escapes, however, this won't happen.

Dan
  • 12,409
  • 3
  • 50
  • 87