Using AngularJS with Django

July 22, 2016 - 6 minutes read

We were updating the interface to one of the most important parts of our app, the Call Center and we decided to leverage the power of Angular 1 and it’s data-bindings and routing aspects and combine it Django’s ORM capabilities and ease of creating APIs. But we faced a problem early on: How do we combine the power of the two?

Using angularJS with Django

Problem

The issue was that if we serve the Angular templates as they are, the syntax would clash with Django’s own templating syntax. For eg, here’s a piece of code from a Django template:

{% if valid_number %}
<span>{{ valid_number }} </span>
{% endif %}

And here’s the same thing written as an Angular template:

<span ng-if="valid_number">{{ valid_number }}</span>

As you can see, the problem arises when Django reads the angular template bindings and thinks they are part of the Django template syntax and attempts to fill them with data. Unfortunately, it is highly likely that you are not passing this data as part of rendering the template and the application will throw many errors.

This was an issue we faced early on about how we should serve our Angular templates. Despite the Angular portion of the application only consuming the APIs provided by the Django server, serving the template from Django would give us this issue. We could just prevent Django from rendering these using some hacks but we also needed to insert some data using the template engine for scripts such as Intercom.io. We had to come up with a way to serve our Angular app, yet avoid Django’s method of rendering the Angular syntax AND insert data as we see fit into the application.

Solution

The way we solved this was by using ui-router. UI router allows us to move all routing logic from Django to Angular. As we move across various routes, Angular will handle the template rendering and application logic such as fetching the data and will consume the APIs provided by the Django application. This means the Django application will only serve the index file which would look like this:

<html>
  <head>
    <script type="text/javascript">
    var token = {{ django_data }};
    </script>
  </head>
  <body>
    <div ui-view style="min-height: 100%;height: 100%;"></div>
  </body>
</html>

Notice how we still use Django to render our token to the template but since we are only serving this one HTML and none of the templates used to render the data, we can safely continue to use Angular syntax within them and ui-router will use these templates within the <div ui-view> tag. Here, ui-view is a DIRECTIVE that tells ui-router where the template must be rendered and all template data will be rendered within this div tag. So our template will look something like this:

<div>{{ data }}</div>

This template syntax will reside in a file of it’s own which UI-Router will use. This file can be any HTML file that UI-Router should be able to recognise.

But another issue that arises is how Django will serve these template files too! Django uses a command called “collectstatic” which collects all resources required by a template and stores them in a static directory from where we can obtain the files necessary but the way Django knows which files to store is by reading the template and finding all the files in <script> and <link> tags. but our templates are not in these script tags! Since UI-router uses it’s own internal HTTP request to fetch the files required, Django does not know to collect these templates!

To solve this issue, we use Gulp and a gulp plugin called gulp-angular-templatecache which takes all our template tags and bundles them into a JS file which we can then reference and link to instead of the template HTML file instead! Our gulp task that does this looks like this:

gulp.task('partials', ['clean'], function () {
  return gulp.src([
    '/{app,assets}/**/*.html',
  ])
    .pipe($.htmlmin({
      empty: true,
      spare: true,
      quotes: true
    }))
    .pipe($.angularTemplatecache('templateCacheHtml.js', {
      module: 'app'
    }))
    .pipe(gulp.dest('/templates/'));
});

This gulp file takes all the HTML files within the “app” and “assets” folder and puts them as Angular TemplateCache objects within a JS file. So in our application when we use this JS file like this:

<script type="text/javascript" src="{{ STATIC_URL }}/templateCacheHtml.js">

Django will automatically collect this JS file and will serve it when a user visits the page. Now when UI-router requests for a template using an HTTP request, Angular realises that the template is already in the TemplateCache and serves that instead of actually querying the server for the file! Neat!

 

 

Tags: , , , ,