Introduction to angularjs $routing services for beginners

The angularjs framework has a built-in $route service that can be configured to handle route transitions in single-page web applications. It covers all the features that we were trying to handcraft using the $location service and additionally offers other very useful facilities. We are going to get familiar with those step-by-step.

Note

Starting from Version 1.2, angularjs will have its routing system delivered in a separate file (angular-route.js) with its own module (ngRoute). When working with the latest version of angularjs, you will need to remember to include the angular-route.js file and declare a dependency on the ngRoute module.

Basic routes definition

Before diving into more advanced usage scenarios, let’s abandon our naïve implementation by converting our route definitions to the syntax used by the $route service.

In angularjs, routes can be defined during the application’s configuration phase using the $routeProvider service. The syntax used by the $routeProvider service is similar to the one we were playing with in our custom $location based implementation:

angular.module('routing_basics', [])
  .config(function($routeProvider) {
    $routeProvider
      .when('/admin/users/list', {templateUrl: 'tpls/users/list.html'})
      .when('/admin/users/new', {templateUrl: 'tpls/users/new.html'})
      .when('admin/users/:id', {templateUrl: 'tpls/users/edit.html'})

      .otherwise({redirectTo: '/admin/users/list'});
  })

The $routeProvider service exposes a fluent-style API, where we can chain method invocations for defining new routes (when) and setting up a default route (otherwise).

Note

Once initialized, an application can’t be reconfigured to support additional routes (or remove existing ones). This is linked to the fact that angularjs providers can be injected and manipulated only in configuration blocks executed during the application’s bootstrap.

 

Tip

The content of a route can be also specified inline using the template property of a route definition object. While this is a supported syntax, hardcoding the route’s markup in its definition is not very flexible (nor maintainable) so it is rarely used in practice.

Recommended :  Exploring the WordPress core files for beginners

Displaying the matched route’s content

When one of the routes is matched against a URL, we can display the route’s contents (defined as templateUrl or template) by using the ng-view directive. The $location-based version of the markup looked before as follows:

<div class="container-fluid" ng-include="selectedRoute.templateUrl">
    <!-- Route-dependent content goes here -->
</div>

With ng-view, this can be rewritten as follows:

<div class="container-fluid" ng-view>
    <!-- Route-dependent content goes here -->
</div>

As you can see, we simply substituted the ng-include directive for ng-view one. This time we don’t need to provide an attribute value, since the ng-view directive “knows” that it should display the content of the currently matching route.

Matching flexible routes

In the naïve implementation, we were relying on a very simple route matching algorithm, which doesn’t support variable parts in URLs. In fact it is a bit of a stretch to call it an algorithm, we are simply looking up a property on an object corresponding to URL’s path! Due to the algorithm’s simplicity, we were using a URL query parameter in the query string to pass around the user’s identifier as follows:

/admin/users/edit?user={{user.id}}

It would be much nicer to have URLs where the user’s identifier is embedded as part of a URL, for example:

/admin/users/edit/{{user.id}}

With the angularjs router, this is very easy to achieve since we can use any string prefixed by a colon sign (:) as a wildcard. To support a URL scheme where the user’s ID is part of a URL we could write as follows:

.when('/admin/users/:userid', {templateUrl: 'tpls/users/edit.html'})

This definition will match any URLs with an arbitrary string in place of the :userid wildcard, for example:

Recommended :  how to create your Site in 5 Minutes with WordPress

/users/edit/1234

/users/edit/dcc9ef31db5fc

On the other hand, routes with an empty :userid, or the :userid containing slashes (/) won’t be matched.

Tip

It is possible to match routes based on parameters that can contain slashes, but in this case we need to use slightly modified syntax: *id. For example, we could use the star-based syntax to match paths containing slashes: /wiki/pages/*page. The route-matching syntax will be further extended in angularjs Version 1.2.

Defining default routes

The default route can be configured by calling the otherwise method, providing a definition of a default, catch-all route. Please notice that the otherwise method doesn’t require any URL to be specified as there can be only one default route.

Tip

A default route usually redirects to one of the already defined routes using the redirectTo property of the route definition object.

The default route will be used in both cases where no path was provided as well as for cases where an invalid URL (without any matching route) triggers a route change.

Accessing route parameter values

We saw that route URLs definition can contain variable parts that act as parameters. When a route is matched against a URL, you can easily access the values of those parameters using the $routeParams service. In fact, the $routeParams service is a simple JavaScript object (a hash), where keys represent route parameter names and values represent strings extracted from the matching URL.

Since $routeParams is a regular service, it can be injected into any object managed by the angularjs Dependency Injection system. We can see this in action when examining an example of a controller (EditUserCtrl) used to update a user’s data (/admin/users/:userid) as follows:

.controller('EditUserCtrl', function($scope, $routeParams, Users){
  $scope.user = Users.get({id: $routeParams.userid});
  ...
})

The $routeParams service combines parameter values from both the URL’s path as well as from its search parameters. This code would work equally well for a route defined as /admin/users/edit with a matching URL: /admin/users/edit?userid=1234.

Reusing partials with different controllers

In the approach taken so far, we defined a controller responsible for initializing the partial’s scope inside each partial using the ng-controller directive. But the angularjs routing system makes it possible to define controllers at the route level. By pulling the controller out of the partial, we are effectively decoupling the partial’s markup from the controller used to initialize the partial’s scope.

Recommended :  Request routing laravel 4 vs laravel 5

Let’s consider a partial providing a screen for editing a user’s data:

<div ng-controller="EditUserCtrl">
    <h1>Edit user</h1>
   . . .
</div>

We could modify it by removing the ng-controller directive as follows:

<div>
    <h1>Edit user</h1>
   . . .
</div>

Instead of that we can define the controller service in the route level as follows:

.when('/admin/users/:userid', {
  templateUrl: 'tpls/users/edit.html'
  controller: 'EditUserCtrl'})

By moving the controller to the route definition level, we’ve gained the possibility of reusing the same controller for different partials and more importantly, reusing the same partials with different controllers. This additional flexibility comes in handy in several situations. A typical example would be a partial containing a form to edit an item. Usually we want to have exactly the same markup for both adding a new item and editing an existing item, but behavior for new items might be slightly different as compared to the existing ones (for example, creating rather than updating when persisting the item).

 

 

 

 

About the author

Deven Rathore

I'm Deven Rathore, a multidisciplinary & self-taught designer with 3 years of experience. I'm passionate about technology, music, coffee, traveling and everything visually stimulating. Constantly learning and experiencing new things.

Pin It on Pinterest

Shares