Tuesday 2 April 2019


How to take PostgreSQL dump from Kubernetes cluster on Google cloud Platform








Almost all the web application has the database. When we deploy our application in Cloud (in this case Google Cloud Platform) it’s quite possible that we put the database on a different POD other than the application POD.

In this section we are going to show, how can we take the Postgres DB dump which is deployed on the Kubernetes cluster.

Assumptions: The postgres pod is already deployed in the Kubernetes cluster.

Steps 

1. Open the browser and go to the  "https://console.cloud.google.com/" 
2. On the GCP menu click on the "Activate Cloud Shell" 

3. Find out the name of the running POD using the command 
yogeshsonawane@cloudshell:~ (Project-1)$ kubectl get pods | grep <Name of deployment or Pod>
e.g. kubectl get pods | grep "mytestApp"

4. Switch to the raw terminal mode i.e. Open a shell in the running Kubernetes POD

        kubectl exec -it <POD Name> -c <Container Name> -- /bin/bash
        kubectl exec -it mytestApp-7c4fb7594c-qd94j   -c datastore -- /bin/bash

In this command "mytestApp-7c4fb7594c-qd94j" is the POD name found from the command in step#3. "DataStore" is the container name.

5. take the pgdump
        /usr/bin/pg_dump --dbname mcmdb -u myappb  > myappdb.sql

6. Open another shell. by clicking on the "Add Cloud Shell Session  button " (+) button displayed on the 
7. copy the dump file from pg datastore cluster to outside. i.e. to the current shell.
8. take the pgdump using the following command
        kubectl cp mytestApp-7c4fb7594c-qd94j:/root/ myappdb.sql  -c datastore .

You can also copy this dump file to the Google Storage bucket using the following command.

gsutil cp myappdb.sql gs://<bucket_name>/<folder_inside_bucket>/

9. Download the dump using the option available in the active shell session.

Tuesday 22 December 2015

Event based communication between controllers.


Every angular application has a single root Scope ($rootScope). All the scopes are its descendants.

Scopes can generate an  events by emitting ($emit) or broadcasting ($broadcast). Apart from generating events, scope can listen to events as well. Its is achieved by using the $scope.$on 

$emit, $broadcast and $on follow the standard "publish / subscribe" design pattern.


Understanding the $scope methods for event based communication between angular controllers

  • $scope.$emit:  This method dispatches the event in the upwards direction (from child to  parent)
  • $scope.$broadcast: Method dispatches the event in the downwards direction (from parent to child)  to all the child controllers.
  • $scope.$on: Method registers to listen to some event. All the controllers which are listening to that event gets notification of the broadcast or emit based on the where those fit in the child parent hierarchy.  

If we consider a case where "grand_child" controller calls the $emits method on its scope. The same "grand_child" controller has also listening to the same event which is emitted by itself. In this situation when "grand_child" calls $emit, the same controller gets its own notification. 

Essentially all the controllers in the hierarchy gets notification for $emit (in upwards direction).
Note : In case of sibling scopes (the scopes which are not in the direct parent child hierarchy) then $emit and $broadcast will not communicate to the sibling scopes.



$rootScope.$broadcast:  $rootScope is the parent of all the scopes. $rootScope.$broadcast will notify the event to all the controllers listening to $rootScope.$on as well as $scope.on



$rootScope.$emit :  We may think that calling $emit method is meaning-less as rootScope do not have any parent. But actually $rootScope.$emit fires an event to all the controllers listening $rootScope.$on event.  The controllers which are listening on $scope.$on have no effect of this emit.




Stopping the event being propagating 

The $emit event can be cancelled by any one of the $scope who is listening to the event.
The $on provides the "stopPropagation" method. By calling this method the event can be stopped from propagating further.

This method is available only for the events which are emitted($emit). The same is not available for $broadcast.

The events which are broadcast can't be stopped. Although we can registered the scope from listening the event. 
$on function returns a function.
.controller('T1Parent',['$scope',function($scope){
   $scope.T1EventVar = '';
   $scope.stopPropagation=false;
   $scope.stopBroadcast = false;
   var fn = $scope.$on('Tree1Event',function(e,arg){
	$scope.T1EventVar = arg;
	if($scope.stopPropagation) {
		e.stopPropagation();  
	}
	if($scope.stopBroadcast){
		fn();  // This will cancel the listening of the event 'Tree1Event'
	}
   });
   $scope.broadCastEvent=function(){
	 $scope.$broadcast('Tree1Event','T1 Parent Brodacated');
   };
   $scope.emitEvent=function(){
	 $scope.$emit('Tree1Event','T1 Parent Emitted');
   };
}])

The complete example can be see on the following plunk. This example demonstrates the emit, broadcast, rootScope.$emit, rootScope.$broadcast, stopping the propagation and cancelling the listening of the event from a particular controller's scope.

Demo http://plnkr.co/edit/0Pdrrtj3GEnMp2UpILp4?p=preview


source code emit-vs-broadcast.js


angular.module('dlgDemo',[])
.controller('GrandParent1',['$scope','$rootScope',function($scope,$rootScope){
   $scope.GrandParent1Var = '';
   //Listening the Tree 1 Child Event
   $scope.$on('T1childEmitEvent',function(e,arg){
	console.log("Hello");
	$scope.T1EventVar = arg;
   });
	// Listening to Tree 2 Grand Parent Event
   $scope.$on('Tree1Event',function(e,arg){
	$scope.T1EventVar = arg;
   });
   $scope.broadCastEvent=function(){
	   console.log("broadCastEvent");
	 $scope.$broadcast('Tree1Event','T1 Grand Parent Brodacated');
   };
   $scope.emitEvent=function(){
	 $scope.$emit('Tree1Event','T1 Grand Parent Emitted');
   };
   $scope.rootBroadcast = function() {
	   $rootScope.$broadcast('Tree1Event','$rootScope.$broadcast');
   };
   $scope.rootEmit = function() {
	   $rootScope.$emit('Tree1Event','$rootScope.$emit');
   };
}])
.controller('T1Parent',['$scope',function($scope){
   $scope.T1EventVar = '';
   $scope.stopPropagation=false;
   var fn = $scope.$on('Tree1Event',function(e,arg){
	   console.log(e);
	$scope.T1EventVar = arg;
	if($scope.stopPropagation) {
		e.stopPropagation();
	}
	if($scope.stopBroadcast){
		fn();
	}
   });
   $scope.broadCastEvent=function(){
	 $scope.$broadcast('Tree1Event','T1 Parent Brodacated');
   };
   $scope.emitEvent=function(){
	 $scope.$emit('Tree1Event','T1 Parent Emitted');
   };
}])

.controller('T1Child',['$scope','$rootScope',function($scope,$rootScope){
	$scope.T1EventVar = '';
	$scope.T1EventVarFromRoot = '';
   $scope.$on('Tree1Event',function(e,arg){
	console.log(e);
	$scope.T1EventVar = arg;
   });
   
   $scope.emitEvent = function() {
	$scope.$emit('Tree1Event','T1 Child Emitted');
   };

   $scope.broadCastEvent=function(){
	 //$scope.$broadcast('Tree1Event','T1 Child Brodacated');
	 $rootScope.$broadcast('Tree1Event','$rootScope.$broadcast');
   };
   $rootScope.$on('Tree1Event',  function(e,arg){
	   $scope.T1EventVar = arg;
   });
   
}])

.controller('GrandParent2',['$scope',function($scope){
   $scope.T1EventVar = '';
   //Listening the Tree 1 Child Event
   $scope.$on('Tree1Event',function(e,arg){
	$scope.T1EventVar = arg;
   });

   $scope.broadCastEvent=function(){
	 $scope.$broadcast('Tree1Event','T2 Grand Parent Brodacated');
   };

   $scope.emitEvent=function(){
	 $scope.$emit('Tree1Event','T2 Grand Parent Emitted');
   };
}])
.controller('T2Parent',['$scope',function($scope){
   $scope.T1EventVar = '';
   $scope.$on('Tree1Event',function(e,arg){
	$scope.T1EventVar = arg;
   });
   
   $scope.emitEvent = function() {
	$scope.$emit('Tree1Event','T2 Parent Emitted');
   };

   $scope.broadCastEvent=function(){
	 $scope.$broadcast('Tree1Event','T2 Parent Brodacated');
   };
}])
.controller('T2Child',['$scope',function($scope){
	$scope.T1EventVar = '';
   $scope.$on('Tree1Event',function(e,arg){
	$scope.T1EventVar = arg;
   });
   $scope.emitEvent = function() {
	$scope.$emit('Tree1Event','T2 Child Emitted');
   };

   $scope.broadCastEvent=function(){
	 $scope.$broadcast('Tree1Event','T2 Child Brodacated');
   };
   
}]);



Source HTML:



Tree 1 : Grand parant

Event Event Listener1
{{T1EventVar}}

Tree 1 : Parent

Stop Propagation Emit event
Deregister the scope from listening event
Event Event Listener1
{{T1EventVar}}

Tree 1 : Grand Child

Event Event Listener1
{{T1EventVar}}

Tree 2 : Grand parant

Event Event Listener1
{{T1EventVar}}

Tree 2 : Parent

Event Event Listener1
{{T1EventVar}}

Tree 2 : Grand Child

Event Event Listener1
{{T1EventVar}}


How to debug minified JavaScript files


We can debug JavaScript files by placing the debug / break points in the dev tools. Generally the JavaScript files on the production are minified.

To debug such minified files, Web browsers provides the "Pretty print" feature which un-minifies the source file.
  • How to un-minify JavaScript file in Chrome
     Open the developer tools (F12) > Source tab > Open the minified script that you want debug  (ctrl + o)  > at the bottom you will see "Pretty print" button ({})




  • How to un-minify JavaScript file in Firefox

      Open the developer tools (F12) > go to Debugger tab > Open the minified that you want debug (ctrl + o) > at the bottom you will see "Prettify source" button ({})


  • How to un-minify JavaScript file in Internet Explorer
      Open the developer tools (F12) > go to Debugger tab > Open the minified that you want debug  (ctrl + o) > at the top icon panel you will see  a button with tooltip (Load the sources mapped to this generated file) to un-minify the JS file



Thursday 17 December 2015


Angular Modal Dialog





ngDialog is the angular directive used for displaying the modal windows in the angular application.



Features
  • With this directive we can create the custom dialog box easily. We can create the dialog with 
    1. Bootstrap theme
    2. Standard theme which is available with directive. The CSS classes can be customized as per your need
    3. and the custom user defined templates
  • We can  put as many buttons as we need on the dialog to take the necessary actions on the button clicks.
    1. These button functions should be defined in the controller that you have assigned to the view. 
    2. e.g if we want to show the two button on the dialog say "Ok" and "Cancel" then we can write the markup as  button="Ok|okFunction,Cancel|cancelFunction 
      • Here the Ok => will create the button with Label "Ok" on the click event of this "Ok button" the okFunction defined in the controller will be called. Similarly another button "Cancel" will be shown on the dialog which is bound to the scope function cancelFunction
Attribute configuration in the directive markup
  1. dialogid : HTML Id of the dialog created
  2. header   : Header text that should appear on the modal dialog
  3. Message : Message text of the modal dialog
  4. button    : buttons those should appear in the modal dialog,  The number of buttons should be ", (comma)" seperated. For each button the function that should get invoked should be contacted with the "| (Pipe)" Operator
    1. e.g  button="OkButton|okFunction,CancelButton|cancelFunction"
Here is the markup 

Bootstrap Theme

you need to included the following JS in your code












     


Standard Theme









     


Custom Theme


     

HTML code





1. 
    
     
     


2.  
     
     



3. 

          
     







Directive Code
(function(){
 'use strict';
 angular.module('ngDialog',[]);
})();
(function(){
 'use strict';
 angular.module('ngDialog').directive('ngDialog',
  directiveFunc);
 directiveFunc.$inject = [ '$templateCache','$filter'];
 
 function directiveFunc($templateCache,$filter) {
  var dialogBoxConfig = {
   theme: 'bootstrap',
  };
  return {
   restrict : 'AE',
   transclude: true,
   scope : {
    id :"@dialogid",
    header:"@header",
    message:"@message",
    button: "@button",
    theme : "@theme"
   },
   link : function(scope,element,attr) { 
    var buttonAttributeText = attr.button;
    if(buttonAttributeText!= undefined && buttonAttributeText!=''){ 
     var buttonList = null;
     var buttonListJSON = [];
     if(buttonAttributeText.indexOf(",") > 0) {
      buttonList = buttonAttributeText.split(",")
     }else {
      buttonList = createArrayFromObject(buttonAttributeText);
     }
     angular.forEach(buttonList,function(buttonDetails,index){
      var buttonAttributes = null;
      if(buttonDetails.indexOf("|") > 0 ){
       buttonAttributes = buttonDetails.split("|");
      }else {
       //debugger;
       buttonAttributes = createArrayFromObject(buttonDetails.trim()); 
      }      
      buttonListJSON.push({'buttonLabel':buttonAttributes[0],'buttonClickEventFunction':buttonAttributes[1]});
      scope.buttonListJSON = buttonListJSON;
     });
    }else {
     throw "No buttons provided. e.g  ";     
    }
    var messageAttributeText = attr.message;
    if(messageAttributeText!=undefined && messageAttributeText!=''){ 
     var messageList = null;
     var messageListJSON = [];
     if(messageAttributeText.indexOf(",") > 0) {
      messageList = messageAttributeText.split(",")
     }else {
      messageList = createArrayFromObject(messageAttributeText);
     }
     angular.forEach(messageList,function(buttonDetails,index){
      
      var messageAttributes = createArrayFromObject(buttonDetails.trim()); 
      messageListJSON.push({'messageLabel':messageAttributes[0]});
      scope.messageListJSON = messageListJSON;
     });
    }else {
     throw "No dialog message body provided. e.g  ";
    }
   },
   //templateUrl : config.modalsDir+'ngDialog.html',
   //templateUrl: 'tmpls/'+theme+'.html',
    templateUrl: function(tElement, tAttrs) {
     var _theme  = '';
     if(tAttrs.theme === undefined ){
      _theme = 'BOOTSTRAP';
     }else {
      _theme = $filter('uppercase')(tAttrs.theme);
     }      
       if (_theme === 'STANDARD') {  return 'tmpls/standard.html';}
       if (_theme === 'CUSTOM') {  return 'tmpls/'+tAttrs.theme+'.html';}
       if (_theme === 'BOOTSTRAP') {  return 'tmpls/bootstrap.html' };
   },
   controller : function($scope) {
    if($scope.theme === undefined){
     $scope.theme = 'bootstrap';
    }
    $scope.hasValue = function(val){
     var value = $scope.$parent[val.trim()];
     return (value !== null && angular.isDefined(value) && value !== '');
    }
    $scope.myclose = function(arg){
     $("#" + $scope.id).css({
      display : "none"
     });
     if(angular.isDefined(arg) && $scope.hasValue(arg)){
      var funcCall = "$scope.$parent."+arg+"()"; 
      $()
      var retValue = eval(funcCall);
     }
    }
   },
  };
 }
})();

angular.module('ngDialog')
 .run(['$templateCache',function($templateCache){
  $templateCache.put('tmpls/standard.html',
   '
' +'
' + '
' + '

{{ header}}

' + '
' + '
{{messageAttributes.messageLabel}}
' + '
' + '
' + '' + '
' + '
' + '
' + '
'); $templateCache.put('tmpls/bootstrap.html', ' '); }]); function createArrayFromObject(object) { var result = []; if (angular.isArray(object)) { //it is array result = object; }else if (object) { result.push(object); } return result; }
CSS :
.ng-dlg-bg > div {
    display: table-cell;
    vertical-align: middle;
    text-align: center;
}
.ng-dlg {
    text-align: left;
    background: #eaeced;
    width: 350px;
    box-shadow: 0 7px 15px #80898f;
    border-radius: 2px;
    margin: 0 auto;
    display: table;
    position: relative;
}
.ng-dlg > h3 {
    font-weight: normal;
    padding: 15px 20px 10px 20px;
    border-radius: 2px 2px 0 0;
    background: #fff;
    border-bottom: 1px solid #dadcdd;
    font-size: 18px;
    color: #676a6f;
    margin: 0;
}
.ng-dlg > p {
    text-align: right;
    padding: 15px 20px;
    margin: 0;
}
.ng-dlg > p > button {
    width: auto;
    padding: 5px 25px;
    min-width: 80px;
    margin: 0 0 0 5px;
}
.ng-dlg > div {
    margin: 15px 20px 0 20px;
}
.ng-dlg > div > p {
    margin: 7px 0 0 0;
    padding: 0;
}

.ng-dlg-bg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: none;
    z-index: 500;
}
.ng-glass {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: #73808c;
    z-index: 499;
    display: none;
}

Licence : MIT

Monday 7 December 2015


Lifecycle of AngularJS directive. 

AngularJS comes with rich set of in built directives which adds a specific behavior to the HTML markes by transforming the DOM elements.
Some examples of directives are ngBind, ngModel.

AngularJS provides a way to create custom directives as well.

In this tutorial we will understand the directive life cycle and how we can create the custom directive in the consecutive one.

In case of ng-app directive, AngularJS is initialized automatically as soon as HTML document is loaded. AngularJS looks for the directive "ng-app" in the HTML elements. This element then becomes the root of the angular application. "ng-app" directive auto initializes the angular application. This process is called "auto bootstrapping" although we can manually bootstrap angular application.

During the bootstrap process, AngularJS
1. Loads the angular module mentioned within the ng-app directive
2. Creates $injector service responsible for DI in the application.
3. Runs the $compile service.

Typical flow diagram having three directive


1.The compilation Phase:

$compile service looks at the text and attributes of the DOM element. Identifies the directives and embedded expressions. Registers watch for these expressions and updates the UI during angular digest cycle. The compile service compiles the DOM from root element and traverse down the DOM by using depth first traversal algorithm.
During this phase DOM element and its attributes are identified as directive. The directive names are normalized using camleCase. e.g.

  • 1. ng-app is normalized as ngApp,
  • 2. my-custom-directive is normalized as myCustomDirective
  • 3. x-my-custom-directive is normalized as myCustomDirective
  • 4. data-my-custom-directive is normalized as myCustomDirective
  • 5. x: my: custom: directive is normalized as myCustomDirective
  • 6. data:my:custom:directive is normalized as myCustomDirective


':', '-' characters are converted to the camelCase
'data', 'x' are removed from the element and attributes.

Linking phase:

2.  Controller functions: 
After compilation controller and followed by pre-linking function is executed respectively for each directive.
controller facilitates the communication between child and parent directive.  The significance of the controller inside the directive is to
1. modify the $scope of the template and
2 if requested by the child controller, this controller function / object is passed to the child controller and both the controllers can communicate with each other

3. Pre link functions :
After this pre-link function is called. This function can be used manipulate the directive template by appending or prepending.  The pre link function always has the private context with its own directive and can't be accessed by the child controllers.

4. . Post link function ;
Finally post-link function is called for each directive. The order of calling this function is exactly opposite to the compile function. Its starts from the last node and moves up till the root element. In most of the cases we can use this function to apply the CSS to the directive templates.

Typical directive example

customDirective.js having compile function
 

 var app = angular.module("demo",[]);
 app.controller("demoCntrl", function($scope,$q,utilService){
  console.log("inside main controller");
  $scope.tableOptions = {
   headerTemplate: true,
   footerTemplatle: true,
   data : [
    {name:'John'},
    {name:'Varghese'},
    {name:'Mike'}
   ]
  }
 });
 app.directive("myCustomTable", ['$compile','utilService', function($compile,utilService){
   return {
  scope :{
   model:"=",
  },
  transclude : false,
  templateUrl : 'tmpl/tablerow.html',
  compile: function($element, $attributes){
   return {
    pre : function($scope, $element, $attributes, controller, transcludeFn) {
     if($scope.model.headerTemplate !== undefined && $scope.model.headerTemplate === true){
     var template = utilService.getTemplate('tmpl/tableHeader.html');
      var x = $compile(template)($scope);
      $element.prepend(x);
     }
     if($scope.model.footerTemplatle !== undefined && $scope.model.footerTemplatle === true){
      var tmpl = utilService.getTemplate('tmpl/tablefooter.html');
      console.log(tmpl);
      var x = $compile(tmpl)($scope);
      $element.append(x);
     }

    },
    post : function($scope, $element, $attributes, controller, transcludeFn){
     
     $element.addClass(".myCustomTable");
    }
   }
  },
  controller : function($scope,$templateCache,$q,$interpolate){
   if($scope.model.footerTemplatle == undefined ){
    $scope.model.footerTemplatle = false;
   }    
  },
   };
 }])
 .run(['$templateCache',function($templateCache){
 $templateCache.put('tmpl/tablerow.html','
{{record.name}}
'); $templateCache.put('tmpl/tablefooter.html', "showing {{model.data.length}} items" ); $templateCache.put('tmpl/tableHeader.html','Name
'); }]); app.factory('utilService',[ '$templateCache','$interpolate','$q',function($templateCache,$interpolate,$q){ var utilService = {}; utilService.getTemplate = function(templatePath){ var template = $templateCache.get(templatePath); var startSym = $interpolate.startSymbol(), endSym = $interpolate.endSymbol(); if (startSym !== '{{' || endSym !== '}}') { template = template.replace(/\{\{/g, startSym); template = template.replace(/\}\}/g, endSym); } return template; }; return utilService; }]);

Tuesday 24 November 2015







HTTP is a stateless protocol. Each time a client retrieves a new information, it opens a seperate connection to the web / application server. The server does not automatically maintains the contextual information of the client. It leads to many difficulties. Typical example being the online store. User adds the products on the cart by visiting various views. 



There are various solutions available to maintain the session.
e.g. using the cookies, URL re-writting and using the hidden fields.



In online store application created using angular we can also maintain the state of the cart across the various views and controllers.

How we can do it in angular?

Angular provides a way to create services using various recipes which can hold the data.


Step 1. Create a service using value recipe. 
Step 2. Create a cart object inside this service.
Step 3. Provide the cart manipulation operations like update, delete, add Cart to this service.
step 4: Inject this service to the controllers in the online store application.
step 5. Angular makes the service available to all the controllers wherever this cart Service is injected. 

When the angular application bootstraps, it creates service which holds the empty cart object. 

All objects in angular being singleton the same object is made available to all the controllers thereby maintaining the state of the cart across the views.



Online store example

In typical shopping cart we buy products on various product / category pages and keep updating the cart. Here are the steps.

Step 1:  Create the angular application file say main.js

var app = angular.module('shopingCart', ['ngRoute']);

app.config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/page1', {
      tempateUrl: 'page1.html',
      controller: 'page1cntrl'
    })
    .when('/page2', {
      templateUrl: 'page2.html',
      controller: 'page2cntrl',
    })
    .when('/showCart', {
      templateUrl: 'cart.html',
      controller: 'cartcntrl',
    })   

    .otherwise({ // default action of route
      redirectedTo: '/page1'
    })
}]);
Step 2: Create the index.html file


    Shopping Cart
 
  
 
Step 3 :  Create a js file called session-service.js

Here we create the custom injectable service having a cart inside using the "value provider recipe". 

'use strict';
function Cart() {
  return {
    'cartId': '',
    'cartItem': []
  };
}
// custom service maintains the cart along with its behavior to clear itself , create new , delete Item or update cart

app.value('sessionService', {
  cart: new Cart(),
  clear: function() {
    this.cart = new Cart();
    // mechanism to create the cart id 
    this.cart.cartId = 1;
  },
  save: function(session) {
    this.cart = session.cart;
  },
  updateCart: function(productId, productQty) {
    this.cart.cartItem.push({
      'productId': productId,
      'productQty': productQty
    });
  },
//delete Item and other cart operations function goes here...
});

Product page 1 and its controller
page1.html

Product 1 Page

Added to Cart

page1cntrl.js

'use strict';
angular.module('shopingCart').controller('page1cntrl',['$scope','sessionService',function($scope,sessionService){
// in this controller the sessionService has been injected as dependency
// retrieve the session information from the service to the scope using the following stt.
    $scope.sessionData  = sessionService;
    $scope.updateCart = function(id,qty) {
    $scope.itemBought = true;
    sessionService.updateCart(id,qty); // call the service method to update the cart.
  };
}]);

page2.html

Product 2 Page

Added to Cart

page2cntrl.js
'use strict';
angular.module('shopingCart').controller('page1cntrl',['$scope','sessionService',function($scope,sessionService){
// in this controller the sessionService has been injected as dependency
// retrieve the session information from the service to the scope using the following stt.
    $scope.sessionData  = sessionService;
 // for demo and understanding purpose we have duplicated the same method in the two controllers.
// how ever we can create the commonMethods which can be accessed from various different controllers.
I will soon be posting how to create the common methods which can be accessed by different controllers.

  $scope.updateCart = function(id,qty) {
   $scope.itemBought = true;
   sessionService.updateCart(id,qty); // call the service method to update the cart.
  };

}]);
cart.html

Cart

Product idproduct Qty
{{cartItem.id}} {{cartItem.qty}}
Cart is Empty
cartcntrl.js
'use strict';
  angular.module('shopingCart').controller("cartcntrl",
            ['$scope','sessionService',
                       function($scope,sessionService) {
                                  $scope.sessionData = sessionService;
                                   $scope.varShowCart = true;
                                   sessionService.save($scope.sessionData);
          }]);


Note:

This session object needs to be stored in local storage like "$window.sessionStorage" , session object or any other mechanism. The current object will be lost once the user refreshes the page.
 

Further reading

There are different recipes (methods) using which we can create custom angular service these are
1. Service
2. Factory
3. Value
4. Constant and
5. $provide

The first  4 are the specialized version of the $provide. For more details you can refer https://docs.angularjs.org/api/auto/service/$provide



Friday 20 November 2015



Question : How can we share information between the two different angular controllers? 

Answer: Inter controller communication in Angularjs can be achieved using the following mechanisms.

1. Using the $rootScope
2. By Using one of the mechanism for creating the custom services in Angularjs.
    These are...
     a) Factory Method
     b) Value Method
     c) Service Method or
     d) Provide Method.

In this article we will use the factory method for inter controller communication in Angularjs

Problem Statement:

We have a List of available Stores in the UI. These list is made available from one controller "storeList".

There is another controller "storeInfo" which displays the store information.

Once the store is selected in the "storeList" controller the corresponding store information should be made available in the "storeInfo" controller which actually glues this information to the view.

Solution :

Code:
Selected Store is: {{selectedStore}}


Controllers
var storeApp = angular.module('storeApp',[])
storeApp.factory('currentCustomer',function($rootScope) {
  var currentCustomer =  {};
  currentCustomer.customerID = 0;
  currentCustomer.customerName = '';
      currentCustomer.getCustomers =  function () {
          return [{CustomerID:1,CustomerName:'Store 1'},
                  {CustomerID:2,CustomerName:'Store 2'},
                  {CustomerID:3,CustomerName:'Store 3'}]; 
      };
      currentCustomer.setCurrentCustomer = function (custObject) {
        this.customerID = custObject['CustomerID'];
        this.ustomerName = custObject['CustomerName'];
        this.publishChanges();
      }; 
      
      currentCustomer.getCustomerID = function(){
        return this.customerID;
      };
  
      currentCustomer.getCustomerName = function(){
        return this.customerName; 
      };      
      currentCustomer.publishChanges = function() {
              $rootScope.$broadcast('custDataChangeEvent');
      };
    return currentCustomer; 
});  
    

// controller storeList

    storeApp.controller('storeList',function($scope,$http,currentCustomer,$filter) {
      $scope.customers = currentCustomer.getCustomers();
      $scope.changeCust = function changeCust(id) {
          var filteredCustomerList = $filter('filter')($scope.customers,{CustomerID:id},true);
          var currCustomer = filteredCustomerList[0];
          currentCustomer.setCurrentCustomer(currCustomer);
      };
    });

      // listen to the events
      storeApp.controller('storeInfo',function($scope,currentCustomer) {
      $scope.$on('custDataChangeEvent',function(){
       $scope.selectedStore = currentCustomer.getCustomerID();
      });
});

Explanation:

All the Objects in AngularJs are singleton.

In this example currentCustomer is the factory service created.  The factory method returns the currentCustomer object consisting of the customerID and customerName attributes along with the necessary methods like
1. get customer List
2. get CustomerId and getCustomerName
3. set customer details.
4. and importantly a method "publishChanges" which actually notifies the updates made in the currentCustomer  object.

To publish the changes we used the $broadcast service provided by angular. Please check my post on the $broadcast and $emit and $on services.

I will be soon posting it.

storeList controller :

It retrieves the customer list from the factory method and keeps it in its controller scope.
Once the user selects the store from the select option the id is passed to the changeCust scope method. From the customer array which available in the controller, object is filtered using the id.  To filter a particular record from the array we have used the $filter service provided by angular.  Please have a look at my post on the filter.   I will be soon posting it.

The selected customer is then set as the current customer using the factory methods setCurrentCustomer

storeInfo controller:

This controller listens to the publish event. As soon as the customer details are updated. currentCustomer factory's publish method broadcasts the changes to all the controllers. The controllers which are listening to this event a callback function is called where we can take the appropriate action against this changes.

in our example we update the customerID information to the scope selectedStore which is glued back to the view.

There are other ways to achieve this. One way is to use the provider recipes like value or factory.
Please check another article http://yogeshtutorials.blogspot.in/2015/11/session-tracking-in-angularjs.html

Thanks.