I'm used to using Django's URLConf, Views (Controllers), and Models setup. It was driving me nuts to see every example out there hard coding their URLs into the templates. For small applications where you only have a single link for a resource, this may not be a big deal, but for even middle sized applications, as soon as you want to change your URLs at all, you have to pretty much sed every instance of that URL.
If you're used to using Django's {% url %}
tag or reverse()
function and want the same functionality within your AngularJS app, then you'll probabaly like this.
- ngRoute
- Be sure to include
angular-route.js
in yourindex.html
- Be sure to include
Inside of your index.html
, add url-manager.js
and make sure ngRoute
is there also:
<script src="/js/lib/angular-route.js"></script>
<script src="/path/to/url-manager.js"></script>
Add both url.manager
and ngRoute
as dependencies in your app:
var app = angular.module('myApp', ['url.manager', 'ngRoute']);
Instead of specifying your routes using the ngRoute
module, you specify them using the urlManagerProvider
's
addUrlPattern
method (this automatically configures ngRoute
):
app.config(['urlManagerProvider', function(urlManagerProvider){
urlManagerProvider
.addUrlPattern('BookListView', '/', {
templateUrl: 'book_list.html',
controller : 'BookListCtrl'
})
.addUrlPattern('BookDetailView', '/books/:id/:slug/', {
templateUrl: 'book_detail.html',
controller : 'BookDetailCtrl'
})
.otherwise({
redirectTo: 'nope.avi'
});
}]);
The addUrlPattern
method takes in three parameters:
- The name of the view (must be unique)
- The URL pattern to match. For example:
/books/:id/:slug/
- A configuration object. This is directly passed to
ngRoute
'swhen
method.
There is also an otherwise
method which is just a wrapper around ngRoute
's otherwise
method.
The url-manager
module includes a directive, alink
, as a convenience function that will output an <a>
tag with the current URL given a view name and keyword arguments:
<div ng-controller="BookListCtrl">
<ul>
<li><alink view="BookDetailView" id="42" slug="the-adventures-of-fred-funnies">The Adventures of Fred Funnies</alink></li>
</ul>
</div>
Assuming there is a view that exists with the name BookDetailView
and has a url pattern of '/books/:id/:slug/'
then the following <a>
tag will be generated (and also replace the <alink>
directive):
<a href="/books/42/the-adventures-of-fred-funnies/">The Adventures of Fred Funnies</a>
Note: The view BookDetailView
is declared in the addUrlPattern()
function.
The <alink>
directive has one required attribute, view
, which specifies the name of the view. Any other additional attribute added will be considered a keyword argument to the URL reverse function. Any attribute that does not match any of the url pattern's keywords will be safely ignored. For example: passing the attributes id
, slug
, and title
with a url pattern of /books/:id/:slug/
, the title
attribute will be ignored and id
and slug
will match thus producing the url /books/42/the-adventures-of-fred-funnies
.
<alink>
supports transclusion thus allowing for the contents of the newly created <a>
tag to contain HTML.
Since, most of the time, data is usually passed around as objects, the <alink>
directive has a special attribute obj
that accepts a JavaScript object. Assume the variable books
is a list of book
objects where each book has the attributes id
, title
, and slug
, the <alink>
example can be simplified to:
<div ng-controller="BookListCtrl">
<ul>
<li ng-repeat="book in boooks"><alink view="BookDetailView" obj="book">{{ book.title }}</alink></li>
</ul>
</div>
Note: The obj
attribute does not require "{{ book }}"
, but "book"
.
Sometimes you may want to create a URL within the controller itself. All that is needed to be done is to inject the urlManager
into your controller and then call its reverse
method:
app.controller('BookListCtrl', function(urlManager, resourceManager, $location){
var book;
var books = resourceManager.getBooks().then(function(){
book = books[0];
$location.url(urlManager.reverse('BookDetailView', book));
// or the second parameter could be built
// $location.url(urlManager.reverse('BookDetailView', {id: book.pk, slug: slugify(book.title)});
});
});
The urlManager.reverse()
takes two arguments:
- The name of the view
- An object of parameters to match against the view's url pattern
A quick demo can be found in the gh-pages
branch or a live demo can be found here