Thursday, October 13, 2016

AngularJS - Route Resolve

The resolve property is used either inside the .when() method of $routeProvider service or .state() method of $stateProvider service. The use of resolve is to make sure that the route transitioning happens only when promises contained inside the resolve property are resolved completely. This is extremely useful in scenarios where the database, services and application are hosted on different servers and there is network latency in getting data. The data that is retrieved from the resolve is stored in user defined property, which can be injected in controllers. This means controller doesn't have to fetch the data by itself.

The resolve property is a map object. The map object contains key/value pairs of:
key - {string}: a name of a dependency to be injected into the controller.
value - {string|function}:
If string, then it is an alias for a service. Otherwise if function, then it is injected and the return value is treated as the dependency. If the result is a promise, it is resolved before the controller is instantiated and its value is injected into the controller.

For more details please follow the ui-router wiki. 



Wednesday, October 12, 2016

AngularJS - "ngRoute vs ui-router"

The ngRoute as well as ui-router, both are used for defining routing in an application. Following are the differences between them:
  • The ngRoute module is created by the AngularJS team, while the ui-router is the third party module.
  • The ng-route implements the routing based on the url, while the ui-router implements the routing based on the state of the application.
  • The ui-router provides everything that the ngRouter module provides along with additional features.
    • Nested states & views
    • Multiple named views
For more details on to routing please refer ngRoute API reference and ui-router wiki.

AngularJS Intellisense in Visual Studio

To get the AngularJS Intelligent in Visual Studio you need to follow 3 simple steps:

Step-1: Download AngularJS extension for Visual Studio from the below link and save the content of the file with name "angualr.intellisense.js".
Step-2: Copy this file to location "C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References" for Visual Studio 2013. 

Step-3: Drag and drop the files "angular.min.js" and "angular-route.min.js" to script.js file.

Step-1 and Step-2 are not required for Visual Studio 2015, since this extension is already included in Visual Studio 2015.


AngularJS - Controller - "Controller as vs $scope"

This the continuation of my previous post. Here I am going to discuss the difference in the two syntax of writing controllers.
  • The "controller as" syntax is the new technique of writing controllers, which was introduced in AngulraJS official release 1.2.0. The $scope is an older technique and is available since the initial version of the AngularJS is released.
  • The "controller as" technique makes code more readable when working with nested scope. Example: Lets say we need to show the data in following way:Controller 
                   Country
                   Country - State
                   Country - State - City
    • Using Older technique: "$scope"
                         Define Controller:
                               angular.module("myApp", [])
                                     .controller("countryController", function($scope) {
                                           $scope.name "India";
                                     })

                                     .controller("stateController", function($scope) {

                                           $scope.name "Karnataka";
                                     })

                                     .controller("cityController", function($scope) {

                                           $scope.name "Bangalore";
                                     });


                         Using Controller:
                               <div ng-controller ="countryController">
                                     {{name}}  
                                     <div ng=controller="stateController">
                                          {{$parent.name}} - {{name}}
                                          <div ng= "cityController">
                                               {{$parent.$parent.name}} - {{$parent.name}} - {{name}}
                                          <div>
                                     <div>
                               <div>                               
    • Using New technique: "controller as"
                         Define Controller:
                               angular.module("myApp", [])
                                     .controller("countryController", function() {
                                           this.name "India";
                                     })

                                     .controller("stateController", function() {

                                           this.name "Karnataka";
                                     })

                                     .controller("cityController", function() {

                                           this.name "Bangalore";
                                     });


                         Using Controller:
                               <div ng-controller ="countryController as countryCtrl">
                                     {{countryCtrl.name}}  
                                     <div ng=controller="stateController as stateCtrl">
                                          {{countryCtrl.name}} - {{stateCtrl.name}}
                                          <div ng= "cityController as cityCtrl">
                                               {{$countryCtrl.name}} - {{stateCtrl.name}} - {{cityCtrl.name}}
                                          <div>
                                     <div>
                               <div>              

  • In older syntax the $scope object need to be injected in controller function, in new syntax (controller as) we don'e need to inject the $scope object,  unless you need it for some other purpose.
There is neither good nor bad in using either of the syntax while writing controllers. Its purely developer's call to use any syntax he/she prefers.

AngularJS - Controller "Controller as" syntax

We have seen in my earlier post the controller code with $scope object. In this post I am going to talk about the controller code with "controller as" syntax.

While creating the controller code with "controller as" syntax, we don't have to inject the $scope object in controller function, instead "this" is being used .

While using "Controller as" syntax don't be in under impression that $scope is not being used. It is still being used behind the scene, just that AngularJS is hiding that.

Defining controller:
angular.module("myApp", [])
            .controller("myController", function(){
                this.message = "Hello World!";
             })
            .controller("employeesController", function($http){
                    var self= this;
                    $http({
                             method: 'get',
                             url: "EmplyeeService.asmx/GetAllEmployees'
                        })
                           .then(
                                       function(response) {
                                           self.employees = response.data;
                                        }, 
                                        function(reason) {
                                            self.error = reason.data;
                                        })
                   })
            .controller("employeeDetailsController", function($http, $routeParams){
                   var self= this;
                    $http({
                             method: 'get',
                             url: "EmplyeeService.asmx/GetEmployees',
                             params: {id: $routeParams.id}

                        })
                           .then(
                                       function(response) {
                                           self.employee = response.data;
                                        }, 
                                        function(reason) {
                                            self.error = reason.data;
                                        })
                   });

Using Controller: through routing
angular.module('myApp', ["ngRoute"])
             .configure( function ($routeProvider){
                   $routeProvider
                          .when("/employees",  {
                                    templateUrl: "Partial/employees.html",
                                    controller: "employeeController as employeeCtrl"
                            })
                          .when("/employee/:id",  {
                                    templateUrl: "Partial/employeeDetails.html",
                                    controller: "employeeDetailsController",
                                    controllerAs: "employeeDetailsCtrl"
                            })
                            .otherwise({
                                    redirectTo: "/home"
                            })
                });

Using Controller: directly in view
<h1 ng-controller= "myController as myCrl">{{myCtrl.message}}   </h1>
<table ng-controller ="employeesControls as employeeCtrl">
      <tr ng-repeat="employee in employeeCtrl.employees">
           <td>
                   {{employee.name}}
           </td>  
      </tr>
</table>     

Below examples summaries the two syntax for defining AngularJS controllers:

Controller code with $scope object:
Define Controller:
angular.module("myApp", [])
            .controller("myController", function($scope) {
                  $scope.message "Hello World!";
            });

Use controller inside the View:
<h1 ng-controller="myController">{{message}}   </h1>


Controller code with "controller as" syntax
Define controller:
angular.module("myApp", [])
            .controller("myController", function() {
                  this.message "Hello World!";

            });

Use controller inside the View:
<h1 ng-controller="myController as myCtrl">{{myCtrl.message}}   </h1>

AngularJS - Routing - "ui-router" - "$stateParams"

This is the continuation of the previous post.

The $routeParams is used for passing the parameters to the web service from the URL.

Lets say now you need to get the department details from the each department from the departments.html page.

Make department as clickable links in the departments.html page and  create a new page for department details. 
Partial view : departments.html
<ul>
    <li ng-repeat ="department in departments">
        <li>
              <a ui-sref ="departmentDetilas({id: department.id})>
                   {{department.name}}
              </a>
       <li>
    </li>
</ul>

Define Routes:
var myApp = angular.module('myApp', ["ui-router"])
                                     .config( function ($stateProvider){
                                          $stateProvider
                                                .state("home",  {
                                                        url: "/home",
                                                        templateUrl: "Partial/home.html",
                                                        controller: "homeController"
                                                })
                                                .state("courses",  {
                                                        url: "/courses",
                                                        templateUrl: "Partial/courses.html",
                                                        controller: "coursesController"
                                                })
                                                .state("departments",  {
                                                        url: "/departments",
                                                        templateUrl: "Partial/departments.html",
                                                        controller: "departmentsController"
                                                })
                                                .state("departmentDetails",  {
                                                        url: "/departments/:id",
                                                        templateUrl: "Partial/departmentDetails.html",
                                                        controller: "departmentDetailsController"
                                                }) 
                                          });

You can use any name for the parameter in state configuration, as long as you are retrieving the parameter with the same name using $stateParams service. In current example we have used parameter name as "id".  

Define Controllers:
var myApp = angular.module('myApp', ["ngRoute"])
                                     .controllers("homeController",  function ($scope){
                                          $scope.message = "Home";
                                     })   
                                     .controllers("coursesController",  function ($scope){
                                           $http({
                                                         method: "get",
                                                         url: "CoursesService.asmx/GellAllCourses"
                                           })
                                               .then(
                                                function(response) {
                                                      $scope.departments = response.data;
                                                 }, 
                                                 function(reason) {
                                                      $scope.error = reason.data;
                                                 });                                          
                                     })                                             
                                     .controllers("departmentController",  function ($scope, $http){
                                           $http({
                                                         method: "get",
                                                         url: "DepartmentService.asmx/GellAllDepartment"
                                           })
                                               .then(
                                                function(response) {
                                                      $scope.departments = response.data;
                                                 }, 
                                                 function(reason) {
                                                      $scope.error = reason.data;
                                                 });
                                     })
                                     .controllers("departmentDetailsController",  function ($scope, $http, $stateParams){
                                           $http({
                                                         method: "get",
                                                         url: "DepartmentService.asmx/GetDepartment",
                                                         params: { id: $stateParams.id }
                                           })
                                               .then(
                                                function(response) {
                                                      $scope.department = response.data;
                                                 }, 
                                                 function(reason) {
                                                      $scope.error = reason.data;
                                                 });
                                     });                                    
                                   
Use $statePatams service to read the parameters from the url. Note that the parameter name "id" is same in both route configuration as well as in $stateParams.id.

AngularJS - Routing - "ui-router"

The ui-router is a third party routing framework for AngularJS. It provides everything what an ng-route provides along with additional features. The ui-router implement routing based on the state of the application where ng-route implements routing based on the route url. Hence views and routes are not tide to the application url in case of ui-router unlike ng-route.


Steps to use the  AngularJS routing module uiRouter:
  • Add the reference for the same in your application.
              <script src="scripts/angular-ui-router.min.js"></script>
  • Include uiRouter as a dependency while creating the module in our application.
              var myApp = angular.module('myApp', ["ui.router"]);
  • Add ui-view directive in the layout page.
             <div class="container">
                 <ui-view>
                         <!-- Here partial templates will be injected -->
                </ui-view>
            </div> 
  • Configuring state using state() method of $stateProvider service.
            $stateProvider.state(stateName, stateConfiguration);

Configuring state in ui-router

A state corresponds to a "place" in the application.

Angular function .configure is used for to define the routes in AngularJS application. The object $stateProvider is injected in the .config() function. The object $stateProvider has the function .state that maps the partial views. You can have as many as .state functions you want, depending on the numbers of routes you are configuring. 

var myApp = angular.module('myApp', ["ui-router"])
                                   .config( function ($stateProvider, $urlRouterProvider){
                                          $urlRouterProvider.otherwise("/abc");                                               
                                          $stateProvider
                                                .state("abc",  {
                                                        url: "/abc",
                                                        templateUrl: "Partial/abc.html",
                                                        controller: "abcController"
                                                })
                                                .state("xyz",  {
                                                        url: "/xyz",
                                                        templateUrl: "Partial/xyz.html",
                                                        controller: "xyzController"
                                                })  
                                                .state("def",  {
                                                        url: "/def",
                                                        templateUrl: "Partial/def.html",
                                                        controller: "defController"
                                                })
                                          });

To configure default route, inject $urlRouteProvider service into .config() function and use .otherwise function to map to the default url. When the default route is defines it means that if we try to access either the route which is not configured or the base route page, it will redirect us to the url which is specified in the .otherwise method.

Using state from main Layout:
Directive ui-sref is used for creating links with ui-router. The ui-sref points to the state of the application.
    <head>
    </head>
    <body>
        <div>
             <a sref="abc"> ABC</a>
             <a sref="xyz"> XYZ</a>
             <a sref="def"> DEF</a>  
        </div>
        <div class="container">
             <ui-view>
                     <!-- Here partial templates will be injected  -->
             </ui-view>
        </div> 
    </body>


Things to Note::
  • To reload the section of a layout use reload() function of object $state. The object $state is provided by the ui-router module.
  • To remove the # from url, use the same mechanism which is being used in earlier post for ng-route, where it is done by enabling html5mode routing.
  •  By default the routes which are configured using the ui-router are case-sensitive. To make a route case insensitive we need to inject $urlMatchFactoryProvider service into the .confige() and call function caseInsensitive(true);. To make all the routes to be case insensitive set the $routeProvider.caseInsensitiveMatch = true. 
                        angular.module('myApp', ["ngRoute"])
                                     .config( function ($stateProvider, $urlMatchFactoryProvider){
                                          $urlMatchFactoryProvider.caseInsensitive(true);
                                          $stateProvider
                                                .state("abc",  {
                                                        url: "/abc",
                                                        templateURL: "Partial/abc.html",
                                                        controller: "abcController",
                                                })
                                                .state("/xyz",  {
                                                        url: "xyz",
                                                        templateURL: "Partial/xyz.html",
                                                        controller: "xyzController"
                                                }) 
                                          });