Multiple Views and Routing

In a single-page app, navigating from one page view to another is crucial. When apps grow more and more complex, we need a way to manage the screens that a user will see as they navigate their way through the app.

We can already support such management by including template code in line in the main HTML, but not only will this in-line code grow large and unmanageable, it will also make it difficult to allow other developers to join in development. Additionally, we can’t copy the URL and send it to our friends because the state of the application needs to be contained in the URL.

Rather than including multiple templates in the view (which we could do with the ng-include directive), we can break out the view into a layout and template views and only show the view we want to show based upon the URL the user is currently accessing.

We’ll break these partial templates into views to be composed inside of a layout template. AngularJS allows us to do that by declaring routes on the $routeProvider, a provider of the $route service.

Using the $routeProvider, we can take advantage of the browser’s history navigation and enable users to bookmark and share specific pages, as it uses the current URL location in the browser.

Installation

As of version 1.2, ngRoutes has been pulled out of the core of Angular into its own module. In order to use routes in our Angular app, we need to install and reference it in our app.

We can download it from code.angularjs.org and save it in a place that we can reference it from our HTML, like js/vendor/angular-route.js.

We can also install it using Bower, which will place it in our usual Bower directory. For more information about Bower, see the Bower chapter.

$ bower install --save angular-route

We need to reference angular-route in our HTML after we reference Angular itself.

<script src="js/vendor/angular.js"></script>
<script src="js/vendor/angular-route.js"></script>

Lastly, we need to reference the ngRoute module as a dependency in our app module:

angular.module('myApp', ['ngRoute']);

Layout Template

To make a layout template, we need to change the HTML in order to tell AngularJS where to render the template. Using the ng-view directive in combination with the router, we can specify exactly where in the DOM we want to place the rendered template of the current route.

For instance, a layout template might look something like:

<header>
  <h1>Header</h1>
</header>
<div class="content">
  <div ng-view></div>
</div>
<footer>
  <h5>Footer</h5>
</footer>

In this case, we are placing all of the rendered content in the <div class="content">, whereas we’re leaving the <header> and <footer> elements intact on route changes.

The ng-view directive is a special directive that’s included with the ngRoute module. Its specific responsibility is to stand as a placeholder for $route view content.

It creates its own scope and nests the template inside of it.

The ng-view directive is a terminal directive at a 1000 priority. Angular will not run any directives on the element at a lower priority, which is most directives (i.e., all other directives on the <div ng-view></div> element are meaningless).

The ngView directive follows these specific steps:

Routes

We use one of two methods to declare all application routes in AngularJS: the when method and the otherwise method.

To create a route on a specific module or app, we use the config function.

angular.module('myApp', []).
  config(['$routeProvider', function($routeProvider) {
    // We'll define our routes in here
  }]);

We’re using special dependency injection syntax here with the [] array. For more information on this syntax, check out the dependency injection chapter.

Now, to add a specific route, we can use the when method. This method takes two parameters (when(path, route)).

This block shows how we can create a single route:

angular.module('myApp', []).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/home.html',
        controller: 'HomeController'
      });
  }]);

The first parameter is the route path, which is matched against the $location.path, the path of the current URL. Trailing or double slashes will still work. We can store parameters in the URL by starting off the name with a colon (for instance, :name). We’ll talk about how to retrieve these parameters using the $routeParams.

The second parameter is the configuration object, which determines exactly what to do if the route in the first parameter is matched. The configuration object properties that we can set are controller, template, templateURL, resolve, redirectTo, and reloadOnSearch.

A more complex routing scenario requires multiple routes and a catch-all that redirects a route.

angular.module('myApp', []).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/home.html',
        controller: 'HomeController'
      })
      .when('/login', {
        templateUrl: 'views/login.html',
        controller: 'LoginController'
      })
      .when('/dashboard', {
        templateUrl: 'views/dashboard.html',
        controller: 'DashboardController',
        resolve: {
          user: function(SessionService) {
            return SessionService.getCurrentUser();
          }
        }
      })
      .otherwise({
        redirectTo: '/'
      });
  }]);

controller

controller: 'MyController'
// or
controller: function($scope) {}

If we set the controller property on the configuration object, the controller given will be associated with the new scope of the route. If we pass a string, it associates the registered controller on the module with the new route. If we pass a function, this function will be associated with the template as the controller for the DOM element.

template

template: '<div><h2>Route</h2></div>'

If we set the template property in the configuration object, Angular will render the HTML template in the ng-view DOM element.

templateUrl

templateUrl: 'views/template_name.html'

If the templateUrl property is set, then your app will attempt to fetch the view using XHR (utilizing the $templateCache). If it finds the template and can load it, Angular will render the template’s contents in the ng-view DOM element.

 
This page is a preview of ng-book.
Get the rest of this chapter plus 600 pages of the best Angular content on the web.

 

Ready to master AngularJS?

  • What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall? Imagine how quickly you could work if you knew the best practices and the best tools?
  • Stop wasting your time searching and have everything you need to be productive in one, well-organized place, with complete examples to get your project up without needing to resort to endless hours of research.
  • You will learn what you need to know to work professionally with ng-book: The Complete Book on AngularJS or get your money back.
Get it now