JC Frane JC Frane - 5 months ago 32
AngularJS Question

Watch service's variable from another module inside a directive

I have two modules "core" and "ui".

The ui module depends on core. This is the code for my core.js :

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

//Services
core.service('httpInformationService', function() {

this.requestCount = 0;
this.responseCount = 0;

this.incrementRequest = function() {
this.requestCount++;
console.log('incrementRequest:' + this.requestCount);
};

this.incrementReponse = function() {
this.responseCount++;
}

this.decrementRequest = function() {
this.requestCount--;
console.log('decrementRequest:' + this.requestCount);
};

this.decrementResponse = function() {
responseCount--;
}

this.getRequestCount = function() {
return requestCount;
}

this.getResponseCount = function() {
return responseCount;
}
});

//Service provider
core.provider("httpServiceInformationProvider", function() {
var provider = {};

provider.$get = ['httpInformationService', function( service ) {
return service;
}];

return provider;
});

//HTTP Interceptor
core.factory('coreHttpInterceptor' ,function( httpInformationService ){
var coreHttpInterceptor = {
request: function(config) {
httpInformationService.incrementRequest();
return config;
},
response: function(response) {
httpInformationService.decrementRequest();
return response;
}
}

return coreHttpInterceptor;
});


var config = {
base_url: enviromnent_url,
}

core.value('config', config);

core.config(function( $interpolateProvider ) {
$interpolateProvider.startSymbol( "[[" ).endSymbol( "]]" );
});

core.config(function( $httpProvider ) {
$httpProvider.interceptors.push('coreHttpInterceptor');
});


This is my ui.js code:

var ui = angular.module('ui',[ 'core' , 'ui.bootstrap' ]);

ui.directive( "shLoadify" , function( httpServiceInformationProvider ){
return {
restrict: "AE",
link: function(scope, element, attrs) {
element.bind( "click", function() {
element.text("Loading...");
element.prop( "disabled", true );
});
},
controller: function($scope) {
$scope.$watch('httpServiceInformationProvider', function(oldValue, newValue){
console.log(oldValue + ' ' + newValue);
}, true);
}
}
});


As you can see i am trying to access requestCount property of httpInfomationService from within my controller using $scope.watch.

The problem is newValue and oldValue is always null. Why is that so?

Answer

Approach 1

If you want to perform some action whenever your requestCount variable gets changed which is part of service, you need to broadcast/emit which then you can listen through on. But in this case you need to pass the scope in your service which is not recommended.

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

app.service('myService',function($rootScope){
  this.requestCount=1
  this.incrementRequestCount=function(){ 
    this.requestCount++
    $rootScope.$broadcast('requestCountChanged', { message: this.requestCount });
  }.bind(this)

})


app.controller('myController',['$scope','myService',function($scope,myService){

  $scope.$on('requestCountChanged', function(event, args) {
      // You will find the updated requestCount in args
    }); 

   $scope.click= myService.incrementRequestCount;

}])

var app1 = angular.module('app1',[]);
    app1.controller('mySecondController',['$scope','myService',function($scope,myService){

      $scope.$on('requestCountChanged', function(event, args) {
            // You will find the updated requestCount in args
        }); 

    }])

Approach 2

Without passing scope in the service

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

app.service('myService',function(){
  this.requestCount=1
  this.incrementRequestCount=function(){ 
    debugger;
    this.requestCount++
  }.bind(this)

})


app.controller('myController',['$scope','myService','$rootScope',function($scope,myService,$rootScope){

   $scope.click=function(){
     myService.incrementRequestCount();
     $rootScope.$broadcast('requestCountChanged', { message: myService.requestCount });

   }  

}])

var app1 = angular.module('app1',[]);
    app1.controller('mySecondController',['$scope','myService',function($scope,myService){

      $scope.$on('requestCountChanged', function(event, args) {

            // You will find the updated requestCount in args
        }); 

    }])

Approach 3

You can only attach watch to those properties which are actually in the scope otherwise you cannot have watch for those properties. So just add requestCount on you scope than you can easily detect its changes using watch and then use broadcast/emit approach.

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

app.service('myService',function(){
  this.requestCount=1
  this.incrementRequestCount=function(){ 
    debugger;
    this.requestCount++
  }.bind(this)

})


app.controller('myController',['$scope','myService','$rootScope',function($scope,myService,$rootScope){

    $scope.requestCount=myService.requestCount
    $scope.$watch('requestCount',function(n,o){
      debugger;
      if(n!=o)
      {
          $rootScope.$broadcast('requestCountChanged', { message: n });
      }
    })
   $scope.click=function(){
     myService.incrementRequestCount();
     $scope.requestCount=myService.requestCount


   }  

}])

var app1 = angular.module('app1',[]);
    app1.controller('mySecondController',['$scope','myService',function($scope,myService){

      $scope.$on('requestCountChanged', function(event, args) {

            // You will find the updated requestCount in args
        }); 

    }])