Skip to content

Providing Django template variables as constants to AngularJS

2012 November 16
by Alec

Over the past few weeks I’ve been using AngularJS to rewrite an enterprise-level configuration web UI containing 90 or so fields. Two-way binding was a natural fit and keeping the data model as a javascript object has made the code quite clean and concise. For a while I was struggling with a good way to handle constants in Angular, including variables coming from the server as Django template variables. This is what I came up with as a solution.

First, redefine the interpolation symbols since they conflict with Django’s:
# module.js

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

Then, create a Constants service which can be injected into controllers on demand. I like the factory() function as it allows you to create private variables as well as exposing a public API:
# services/constants.js

angular.module('app.services')
.factory('Constants', function(DjangoConstants) {
  // define UI constants here
  var constants = {
    customSelect: "Custom",
    keyAudio: "audio"
  };
  // pull in the django constants
  angular.extend(constants, DjangoConstants);
 
  return {
    get: function(key) {
      return constants[key];
    },
    // this is a handy way to make all constants available in your HTML 
    // e.g. $scope.c = Constants.all() 
    all: function() {
      return constants;
    }
  };
});

Finally, pass the django constants to the main module via the constant() method:
# snippet of config.html, a django partial

<script src='{{ STATIC_URL }}js/lib/angular/angular.js'></script>
<script src="{{ STATIC_URL }}js/config/module.js"></script>
<script type="text/javascript">
  // inject some constants from django
  angular.module('app').constant("DjangoConstants", {
    serverName: '{{ server.host }}',
    csrfToken: '{{ csrf_token }}'
  });
</script>

Usage:
# controllers/input.js

function InputCtrl($scope, Constants) {
  $scope.c = Constants.all();
  $scope.audio = $scope.m.in[Constants.get("keyAudio")];
  ...
});

And voila! You now have a central place to access all constants, with zero global variables!

6 Responses
  1. November 24, 2012

    DougJune 28, 2012This was sooooo very hepflul but also raised more then a few questions in my mind that maybe you can address. I’m building a website and it has a similar type of structure to what your presentation does. There is a top menu bar that allows a content pane to be loaded into the ng-view directive. Here is where I’m running into complexity / undesireables. The sub pages are very complex and have a lot of angular / javascript / business logic in them. Putting all the controllers into one file seems wasteful because then essentially all logic for all pages is loaded in one load and upfront. If you include the controller / script in the subpages when ng-view loads (which it does correctly) you cannot use Chrome / Firefox to see the additionally loaded scripts. Which makes for harder development.Ideas / Suggestions?

  2. April 24, 2013

    Thanks for the post. I’m starting out with Angular and Django myself. Just a question really, is that a reason why you decided to created a django constant directive as opposed to simply using ng-init?

    • Alec permalink*
      June 10, 2013

      Nai,

      I hadn’t really explored ng-init at the time I devised this solution, but it looks like a decent alternative for using such constants in local templates. However, you wouldn’t be able to use those constants elsewhere in your app; say in a service, controller, or even another template.

  3. July 29, 2014

    Here is my take on this problem (ultimately using providers) http://bahmutov.calepin.co/inject-valid-constants-into-angular.html

Trackbacks and Pingbacks

  1. Python Django和Angular.js模板标签冲突的解决方式 | 极客我爱你 geek521.com

Comments are closed.