AngularJS controllers communicating with the Django application through Ajax, often require URLs, pointing to some of the views of your application. Don’t fall into temptation to hard code such a URL into the client side controller code. Even worse would be to create Javascript dynamically using a template engine. There is a clean and simple solution to solve this problem.
Note
Until version 0.7 django-angular reversed all existing URLs of a project and created an object exposing them to Javascript. Documentation for now deprecated approach is available here.
Starting with version 0.8, django-angular provides a new way to handle URLs, which offers the reversing functionality directly to AngularJS modules.
This service is provided by djangoUrl.reverse(name, args_or_kwargs) method. It behaves exactly like Django’s URL template tag.
django-angular encodes the parameters passed to djangoUrl.reverse() into a special URL starting with /angular/reverse/.... This URL is used as a new entry point for the real HTTP invocation.
<script src="{% static 'djangular/js/django-angular.js' %}"></script>
<script>
var my_app = angular.module('MyApp', ['ng.django.urls', /* other dependencies */]);
</script>
The djangoUrl service is now available through dependency injection to all directives and controllers.
settings.py file:
MIDDLEWARE_CLASSES = (
'djangular.middleware.DjangularUrlMiddleware',
# Other middlewares
)
Warning
This must be the first middleware included in MIDDLEWARE_CLASSES
Using this approach adds some magicness to your URL routing, because the DjangularUrlMiddleware class bypasses the HTTP request from normal URL resolving and calls the corresponding view function directly.
The reversing functionality is provided by:
djangoUrl.reverse(name, args_or_kwargs)
This method behaves exactly like Django’s URL template tag {% url 'named:resource' %}.
A typical Angular Controller would use the service djangoUrl such as:
var myApp = angular.module('MyApp', ['ng.django.urls']);
myApp.controller('RemoteItemCtrl', ['$scope', '$http', 'djangoUrl', function($scope, $http, djangoUrl) {
$scope.loadItem = function() {
var fetchItemURL = djangoUrl.reverse('namespace:fetch-item');
$http.get(fetchItemURL).success(function(item) {
console.log('Fetched item: ' + item);
}).error(function(msg) {
console.error('Unable to fetch item. Reason: ' + msg);
});
}
}]);
and with args:
$http.get(djangoUrl.reverse('api:articles', [1]))
or with kwargs:
$http.get(djangoUrl.reverse('api:articles', {'id': 1}))
If you want to override reverse url, e.g. if django app isn’t on top level or you want to call another server it can be set in .config() stage:
myApp.config(function(djangoUrlProvider) {
djangoUrlProvider.setReverseUrl('custom.com/angular/reverse/');
});
Warning
The path of request you want to reverse must still remain /angular/reverse/ on django server, so that middleware knows it should be reversed.