Monday, June 30, 2014

AngularJS for Beginners: Route


Route
AngularJS has a robust routing mechanism. It supports hash-based routing. A template mechanism called "layout template" is used for routing. We break out the view into a layout template and partial view templates. The layout template is common for all views. The partial templates are included into this layout template depending on the current "route" - the view that is currently displayed to the user.

Routes in AngularJS are declared using the $routeProvider, which is the provider of the $route service. This service makes it easy to wire together controllers, view templates, and the current URL location in the browser.

Installation
In order to use routes in our AngularJS app, we have to install and reference it in our app. We can download it from https://code.angularjs.org and save it in a place that we can reference it from our HTML. The reference of angular-route must be followed by the reference of AngularJS itself.
 <script src="angular.min.js"></script>  
 <script src="angular-route.js"></script>  
We have to reference the ngRoute module as a dependency in our app module:
  var myModule = angular.module('myModule', ['ngRoute']);
Layout template using ng-view
To make a layout template, we have to tell AngularJS where to render the template. Using the ng-view directive in conjunction with the $route service, we can specify exactly where in the DOM we want to place the rendered view template of the current route. The role of the ng-view directive is to include the rendered view template for the current route into the layout template.  Each time the current route changes, the included view changes with it according to the configuration of the $route service.

Look at the following code snippet of a layout template:
  <header>  
      <h1>Header</h1>  
 </header>  
 <div class="content">  
      <div ng-view></div>  
 </div>  
 <footer>  
      <h2>Footer</h2>  
 </footer>  
In this case, we are placing all of the rendered content in the <div class="content">, more specifically in the <div> containing the ng-view directive. Other elements like <header> and <footer> will not be affected due to route changes.

Routes
We use Angular module’s config method to create route. Two methods of $routeProvider are used for declaring route: the when method and the otherwise method.  See the following code snippet:
 var myModule = angular.module('myModule', ['ngRoute']);            
 myModule.config(function ($routeProvider) {                 
      $routeProvider  
           .when('/view1', {  
                controller: 'BooksController',  
                templateUrl: 'View1.html'  
           })  
           .when('/view2', {  
                controller: 'BooksController',  
                templateUrl: 'View2.html'  
           })       
           .otherwise({   
                redirectTo: '/view1'   
           });                      
 });       
To add a new route definition to the $route service, the when method is used. This method takes two parameters (when(path, route)). The first parameter is the route path, which is matched against the path of the current URL i.e. the $location.path. The second parameter is the configuration object, which determines what should be done if the route in the first parameter is matched. In the configuration object, we can set properties like controller, template, templateURL, resolve, redirectTo etc. In the above example, we used templateUrl and controller.     

If the templateUrl property is set, path or function that returns a path to an html template that should be used by ngView.

If we set the controller property on the configuration object, the controller given will be associated with the new scope of the route.

When no other route definition is matched, the otherwise method provides route definition that will be used for changing route.

resolve
If we set the resolve property, an optional map of dependencies will be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess event is fired. If any of the promises are rejected the $routeChangeError event is fired. See the following code snippet:
 resolve: {  
      'dataMap': ['$http', function($http) {  
           return $http.get('/api').then(  
                function success(resp) { return response.data; }  
                function error(reason) { return false; }  
           );  
      }]  
 }  
In the above example, resolve sends the $http request off and fills the value of ‘data-map’ as the result of the request. The ‘dataMap’ key of the map above will be injected into our controller, so it can be retrieved in the controller. 

$routeParams
We can store parameter in the URL by the name of the parameter with a colon before it (for example, :bookId). The $routeParams service allows you to retrieve the current set of route parameters. Let us set up a route like the following:
 $routeProvider  
      .when('/view1/:bookId', {  
           controller: 'BooksController',  
           templateUrl: 'View1.html'  
      })  
Now, AngularJS will populate the $routeParams with the key of :bookId, and the value of key will be populated with the value of the loaded URL. If the URL /view1/101 is loaded in the browser, then the $routeParams object will look like:
 { bookId: '101' }  
In order to access to these variables in the controller, we need to inject the $routeParams in the controller:
 myModule.controller('BooksController', function($scope, $routeParams) {  
      // $routeParams can be accessed from here  
 });  
Full Example
Here is a full example of route. Three separate html files are used in this example: first one (routeExample.html) for layout template and defining route and others (View1.html and View2.html) for partial template views.

routeExample.html
 <!DOCTYPE html>  
 <html ng-app="myModule">  
 <head>  
    <title>Learning AngularJS</title>  
    <script src="angular.min.js"></script>  
       <script src="angular-route.js"></script>  
 </head>  
 <body>  
      <div id="container">  
           <div ng-view=""></div>  
      </div>  
        
      <script>                  
           var myModule = angular.module('myModule', ['ngRoute']);                 
             
           // set route provider  
           myModule.config(function ($routeProvider) {                 
                $routeProvider  
                     .when('/view1', {  
                          controller: 'BooksController',  
                          templateUrl: 'View1.html'  
                     })  
                     .when('/view2', {  
                          controller: 'BooksController',  
                          templateUrl: 'View2.html'  
                     })       
                     .otherwise({   
                          redirectTo: '/view1'   
                     });                      
           });            
        
        
           myModule.factory('myService', function () {  
                var bookList = [  
                     {name:'The Tempest',   
                          author:'William Shakespeare'},  
                     {name:'Gitanjali',   
                          author:'Rabindranath Tagore'},  
                     {name:'Harry Potter',   
                          author:'J. K. Rowling'},  
                     {name:'The Da Vinci Code',   
                          author:'Dan Brown'},  
                     {name:'A Brief History of Time',   
                          author:'Stephen Hawking'},  
                     {name:'Tell Me Your Dreams',   
                          author:'Sidney Sheldon'}  
                ];  
                  
                var serviceInstance = {};  
                  
                serviceInstance.getBooks = function () {  
                     return bookList;  
                };  
                  
                serviceInstance.addBook =   
                     function (bookName, bookAuthor) {  
                          bookList.push({   
                               name: bookName,   
                               author: bookAuthor   
                          });  
                     };  
                  
                return serviceInstance;                 
           });            
             
             
           myModule.controller('BooksController',   
                function BooksController($scope, myService) {  
             
                     $scope.bookList = myService.getBooks();  
                  
                     $scope.add = function() {  
                          myService.addBook(  
                               $scope.bookName,   
                               $scope.bookAuthor  
                          );  
                     };  
           });                      
       </script>  
 </body>  
 </html>  
View1.html
 <div>  
      <h1>  
           View 1 loaded  
      </h1>  
      <br>  
      List of books:  
      <br>                  
      <ul>  
           <li ng-repeat="book in bookList">  
                {{book.name}} -- {{book.author | uppercase}}   
           </li>  
      </ul>  
      Book name: <input type="text" ng-model="bookName" />  
      Author: <input type="text" ng-model="bookAuthor" /> <br>  
      <button ng-click="add()">Add</button>  
      <br><br>  
      <a href="#/view2">Load view 2</a>  
 </div>  
View2.html
 <div>  
      <h1>  
           View 2 loaded  
      </h1>  
   
      <ul>  
           <li ng-repeat="book in bookList">  
                {{book.name}} -- {{book.author | uppercase}}   
           </li>  
      </ul>  
      <br>  
      <a href="#/view1">Load view 1</a>  
 </div>  
The browser should display the following output:



Clicking the link below will show the following: