Check out these related webinars…
Using the Route Service
In a previous lab we implemented a single page application (SPA) using ng-include. It had a few shortcomings. We could not bookmark and share views and the back button navigation was not supported.
There was another subtle problem that we did not talk about until now. We used a single monolithic controller to manage all views. It is technically possible for each view template to have its own controller. But the overall task of controlling the flow of views has to be done by a central controller. This is fine for a small scale application. But generally its not a good idea to have a single controller that has too many different responsibilities.
We will now convert the application to use the $route service. We will address all of the above mentioned issues with our current application.
1. Setting Up The Environment
1.1. Start the Web server if it has been stopped.
2. Add Route Service to Application
Code for the $route service is not included in the core AngularJS distribution. You will need to download it separately. To save time the distribution for the $route service is already downloaded for us.
2.1. Using Windows Explorer, copy the C:LabFilesjsangular-route.js file over into the js folder. To let you read the code and debug it better we have the non-minified version in that folder. Now we will refer to the script from our HTML file.
2.2. Open store/index.html in an editor.
2.3. Add the code for the $route service as shown below.
<script src="../js/angular.js"></script>
<script src="../js/angular-route.js"></script>
<script src="store.js"></script>
2.4. Save changes.
3. Thinking About the Architecture
Let’s take a moment to devise the architecture of our application. We have essentially two views – product list and product details. How many different controllers will we need? For a simple application like this we can have two completely independent controllers for these views. A more complex application may require some kind of coordination between the views such as share model data. Such a controller will need to be added as a parent of the view specific controllers. We will not need to build such a controller right now.
Next, let’s think about the URL structure of our views. This is a step that is crucial before you start to write any code. A well thought out URL structure can simplify SPA development. With that in mind, let’s go with this scheme:
3.1. Product list view: /store/#/catalog
3.2. Product details view: /store/#/product/10001. Where 10001 is a sample product ID.
4. Set up the Route Table
4.1. Open store/store.js in an editor.
4.2. Add a dependency to the ngRoute module from our module as shown in bold. Make sure you enter the quote.
angular.module("storeApp", ["ngRoute"])
4.3. Below that line add this code to setup the route table.
.config(function ($routeProvider) {
$routeProvider.when("/catalog", {
templateUrl: "list.html"
})
.when("/product/:productId", {
templateUrl: "details.html"
})
.otherwise("/catalog");
})
- Note a few things:
- The otherwise() method sets up the default path when the path in the URL does not match anything in the route table.
- Note how we are passing the product ID parameter in the path.
- The paths like “/catalog” appear in the URL segment identifier (after #). They are declared using the absolute form (starting with “/”). But the templateUrl property is relative to the current page. AngularJS will fetch the view template files using HTML using this URL.
4.4. Save changes.
5. Develop the Product List Controller
Previously our catalogCtrl controller was responsible for both listing the products and showing details of a product. We will now separate out these concerns in two separate controllers.
5.1. In store.js add a new controller like this.
.controller("productListCtrl", function($scope, catalogSvc) {
$scope.productList = null;
function init() {
catalogSvc.fetchProductList().then(
function(response) {
$scope.productList = response.data;
});
}
init();
})
5.2. Save changes.
5.3. Open list.html.
We will need to use the productListCtrl controller here. We can not add it to the top level div tag here since ng-controller and ng-repeat can not be applied to the same tag. So we will need to create a new top level div tag.
5.4. Wrap the entire content of list.html in a new div tag as follows.
<div ng-controller="productListCtrl">
... Existing content ...
</div>
5.5. Save changes.
Great. All we have to do now is use the ng-view directive to show the view template that matches the current URL address.
5.6. Open index.html. Replace these lines:
<div ng-controller="catalogCtrl">
<ng-include src="viewTemplate"></ng-include>
</div>
With:
<div ng-view></div>
5.7. Save changes.
6. Test Changes
We can now test out the product list view.
6.1. Open a browser and enter the URL: http://localhost/store/
6.2. You will see the usual product list page.
6.3. Look at the address of the page. It should be http://localhost/store/#/catalog
Because of our catch all route .otherwise(“/catalog”) system redirected the page to the default path. Also, because the path has “/catalog”, ng-view has loaded list.html.
7. Develop the Product Details Controller
7.1. In store.js add a new controller as follows.
.controller("productDetailsCtrl", function($scope, catalogSvc, $routeParams) {
$scope.selectedProduct = null;
function init() {
var productId = $routeParams["productId"];
catalogSvc.fetchProductDetails(productId).then(function(response) {
$scope.selectedProduct = response.data;
});
}
init();
})
Note how we are getting the product ID from the path using the $routeParams service.
7.2. Save changes.
7.3. Open details.html.
7.4. Wrap the entire content in a top level div tag so we can use the newly developed controller.
<div ng-controller="productDetailsCtrl">
... Existing content ...
</div>
7.5. Save changes.
8. Implement Navigation
We will now need to set up navigation so that clicking on a product’s name in the details page can take us to the details page.
8.1. Open list.html.
8.2. Modify the a tag as follows.
- Remove the ng-click directive entirely.
- Set the href to the path of the details view.
<a href="#/product/{{product.id}}"><h4>{{product.name}}</h4></a>
8.3. Save changes.
9. Test Changes
9.1. Refresh the browser that is showing: http://localhost/store/
9.2. Click on a product name.
9.3. You will most likely see a badly formatted page. This is because AngularJS has stubbornly cached the details.html view template. But make sure that the URL address has changed to something like http://localhost/store/#/product/1002
Try refreshing the page and you should see the correct details view.
9.4. Hit the back button of the browser and you should be able to navigate back to the list page.
9.5. Test for bookmarking and link sharing by entering this URL directly in a new browser tab: http://localhost/store/#/product/1002
9.6. Close all open files.
This is the last step in this lab.
10. Review
In this lab, we enhanced the previously developed SPA using the $route service. Now our application has a few advantages:
10.1. Completely independent controllers manage each view. This will let us develop complicated views relatively easily.
10.2. Views can now be book marked.
10.3. Back and forward navigation works just like normal web browsing.
Related Webinars
Related Training
Introduction to Responsive Web Development with AngularJS and Bootstrap