Check out these related webinars…
The Route Service
1. Introduction to the Route Service
- AngularJS has an add-on service called $route that lets us develop complex single page applications.
- The primary responsibility of the service is to map the URL to external view template HTML files. When the URL changes, the service loads in the associated view HTML file. Example:
- When URL is /checkout.html#/cart show the shopping cart view template shopcart.html.
- When URL changes to /checkout.html#/shipping show the shipping method selection view template ship.html.
- When URL changes to /checkout.html#/billing show the billing view template payment.html.
- Basically, $route improves upon the model offered by ng-include to load an external HTML template file. Instead of referring to the HTML file names when loading a view, you navigate to a different URL. This allows the user to bookmark a view and navigate back using the back button.
Introduction to the Route Service
Just like ng-include, the $route service loads views from external HTML template files. Except it improves the process. The application developer sets up a map between the URL and view HTML files. As the user clicks on a link, the URL address changes. The $route service constantly watches the URL. When it detects a change in the URL, it loads in the associated view HTML file using Ajax and adds it to the DOM. Any previously displayed view is unloaded.
2. Downloading the Route Service Code
- The $route service is not available from the core AngularJS library. You will need to download it separately.
- Go to angularjs.org and click the Download button.
- Click Browse additional modules link.
- Download angular-route.min.js from that page.
3. Using the Route Service
- Add the route service script after AngularJS.
<script src="angular.js"></script>
<script src="angular-route.min.js"></script>
- Add dependency to the ngRoute module from your application’s module.
angular.module("MyApp", ["ngRoute"])
4. Setting up the Route Table
- The route table maps URL to external view files.
- The table is set up using the provider of the $route service ($routeProvider) at the configuration phase of the application.
angular.module("MyApp", ["ngRoute"])
.config(function ($routeProvider) {
$routeProvider.when("/cart", {
templateUrl: "shopcart.html"
})
.when("/shipping", {
templateUrl: "ship.html"
})
.when("/billing", {
templateUrl: "payment.html"
})
.otherwise("/cart");
})
.controller("CheckoutCtrl", function($scope) {
};
- Note: There can only be one route table per application.
Setting up the Route Table
The route table needs to be set up before the $route service is instantiated. So, we must do that at configuration phase. We will need to use the provider of the service $routeProvider since the $route service is not yet created.
The when() method of $routeProvider takes two arguments:
I. A path.
II. An object that maps to the path. The templateUrl property of the object provides the URL to the external view template. This URL is relative to the main page.
The otherwise() method takes a path that the router redirects to when the path in the URL does not match any path in the route table.
5. URL Fragment Identifier
- By default $route service maps URL fragment identifier to external view templates. A fragment identifier is the part of the URL that comes after #. Example:
- This default behavior actually comes from $route’s dependency on the $location service which is discussed in more detail later.
- Later we will learn how to map actual URL paths for a cleaner URL. Example:
6. Showing the Views
- The main entry point HTML of the application shows the view mapped to the current URL using the ng-view directive. This directive is made available by the ngRoute module.
- Example application entry point checkout.html.
<body ng-app="MyApp" ng-controller="CheckoutCtrl">
<h1>Checkout</h1>
<div ng-view></div>
</body>
- As the URL changes, the $route service will fetch the associated view template using Ajax and add it to the DOM as a child of the element where ng-view is used. For example, if the URL is checkout.html#/billing then payment.html will be fetched and added to the DOM.
- Note: $route aggressively caches the external view HTML files. During development this can be a problem. Use your browser’s dev tools to disable caching or use Chrome’s incognito mode to remove cache after every test.
7. Navigation
- You can use simple hyperlinks to navigate between the views. For example:
<a href="#/shipping">Shipping</a>
<a href="#/billing">Billing</a>
- As the user clicks on a link the URL will change and the $route service will render the associated view HTML.
- For programmatic navigation and to work with URL parameters, we will need to make use of the $location service. We will discuss this next. Example:
<a href="" ng-click="showShipping()">Shipping</a>
<a href="#/billing?orderId=10001">Billing</a>
8. The $location Service
- This is a service available from the core AngularJS framework that let’s you read and modify the URL. Example URL:
- $location.path() returns the path in URL fragment – “/ext1/ext2”.
- $location.path(“/new”) will change the path in fragment. The URL will become:
- $location.search() returns an object where each property is a URL parameter. Example:
var params = $location.search();
var who = params.name; //Returns "Daffy".
- $location.search(obj) updates the URL parameters using the properties of the supplied object. Example:
var params = {name: "Bugs", id: 1001};
$location.search(params);
//Fragment is now: #/ext1/ext2?name=Bugs&id=1001
9. Programmatic Navigation
- In some situations, navigation using just hyperlinks may not be sufficient. For example, validate user input before navigating to the next view. To do this, we will use the $location.path() method.
- Example:
.controller("CheckoutCtrl", function($scope, $location) { $scope.showShipping = function() { //Do validation. If all OK go to shipping //... $location.path("/shipping"); }; } <a href="" ng-click="showShipping()">Shipping</a>
Programmatic Navigation
In the example above, we wish to execute some business logic before navigating to the next view. To do that we have attached the showShipping() controller method to the hyperlink. This method uses $location.path(“/shipping”) to change the URL and thereby initiates a navigation. The $route service will detect this change and show the view associated with the new path.
10. Controllers for the Views
- You can have a single controller for all views. This controller contains the ng-view directive and all views are embedded within it. This approach is suitable for simpler applications.
- You can also assign a separate controller for each view. This approach is better when views are complex and having all the controller logic in a single controller is not manageable.
- If you use a separate controller for each view, you can still continue to use a single controller that wraps all the views. This allows you to share data between the views through the global controller.
- The global controller is created only once when the main page (that contains ng-view) is loaded. A view specific controller is instantiated every time that view is loaded using ng-view.
11. Example Controllers for Views
- In this example, we have a global controller for all views and each view has its own controller. The global controller is used to share data between the views.
.controller("CheckoutCtrl", function($scope) {
$scope.order = {total: "$100.00", ...};
})
.controller("ShippingCtrl", function($scope) {
$scope.shippingData = {carrier: "UPS", ...};
})
//checkout.html – The main file
<body ng-app="MyApp" ng-controller="CheckoutCtrl">
<h1>Checkout</h1>
<div ng-view></div>
</body>
//ship.html
<div ng-controller="ShippingCtrl">
Order total: {{order.total}}. <!-- Shared data -->
Shipping carrier: {{shippingData.carrier}}.
</div>
Example Controllers for Views
In the example above, CheckoutCtrl is the global controller. All views are embedded within it. This controller is used to share data between the views. Each view has its own controller. ShippingCtrl contains the logic to manage the shipping view (ship.html). This approach allows us to break up the controller logic and simplify development.
12. Passing URL Parameters
- In order to allow bookmarking and sharing of links for a view anywhere within the navigation flow, you will need to use URL parameters. This allows a view to initialize without relying on any other view.
- For example, for a product details view we should store the product ID in the URL so that it can be bookmarked and shared.
- There are two ways we can provide parameters in the URL:
- Using query parameters: “#/product?productId=XYZ”
- Using route parameters: “#/product/XYZ”
13. Accessing Query Parameters
- Use $location.search() to get the query parameters.
- Example URL fragment: #/product?productId=XYZ
.controller("ProductCtrl", function($scope, $location) {
var params = $location.search();
$scope.productId = params.productId;
})
14. Configuring Route Parameters
- Since a route parameter appears in the path, we must configure the route table accordingly. A parameter is added to the path using the :name format. Example:
.config(function ($routeProvider) {
$routeProvider.when("/product/:productId", {
templateUrl: "/product.html"
});
})
- The route above will match as follows:
-
/product/19202 – Will match.
-
/product – Will not match.
-
/product/10292/1292 – Will not match.
-
- A path can have multiple such parameters.
15. Accessing Route Parameters
- Use the $routeParams service to read the route parameters.
.controller("ProductCtrl", function($scope, $routeParams) {
$scope.productId = $routeParams["productId"];
16. HTML5 Mode
- By default, $location and $route work with paths in a URL fragment identifier. For a cleaner URL (without the #), you will need to enable HTML5 mode. Example:
- HTML5 mode:
- Legacy mode:
- HTML5 mode will only work in a browser that supports the HTML5 History API. In older browsers, AngularJS will fall back to the default mode of using the URL fragment identifier.
- Enable HTML5 mode using the $locationProvider.
.config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when("/cart", {
templateUrl: "shopcart.html"
});
}
17. Using the HTML5 Mode
- Set the base path of the URL using the tag. For example, if the entry point of the application is then add this within the tag:
<base href="/app/"> <!-- href must end with / -->
- In the route table, all paths and template file URLs will be relative to the base. Example:
$routeProvider.when("/cart", {
templateUrl: "shopcart.html"
});
- Browser will load the template from /app/shopcart.html when document’s location changes to /app/cart.
- Navigation links will be relative to the base URL. Example:
<a href="cart">Shopping Cart</a>
- This will set the address URL to and display the view from /app/shopcart.html in ng-view.
18. Bookmarking HTML5 Mode URL
- Since the HTML5 mode changes the actual path of the URL, bookmarking becomes problematic. For example can not be bookmarked because “/cart” is a path only understood by the $route service and not by the server. Requesting that URL from the server will return a 404.
- To solve this problem, you will need to configure the web server. You need to configure it such that a request for “/app/cart”, “/app/shipping”, etc. is resolved by returning the entry point of the application “/app/index.html”.
- Once the entry point HTML loads, AngularJS will route based on the path in the URL.
19. Summary
- The $route Service lets us build a SPA with support for bookmarking and back button navigation.
- The route table maps the URL to view template files.
- By default, the URL path in a fragment identifier is mapped to view templates. But in HTML5 mode, the entire URL path can be mapped.
- HTML5 mode needs special server side configuration.
- You can supply parameters to the URL.
Related Webinars
Related Training
Introduction to Responsive Web Development with AngularJS and Bootstrap