11

Why can't I watch a object in a service. Ive got a simple variable working, but a object wont work. http://plnkr.co/edit/S4b2g3baS7dwQt3t8XEK?p=preview

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

app.service('test', ['$http', '$rootScope',
            function ($http,   $rootScope) {

  var data = 0;
  var obj  = {
                "data": 0
              };

  this.add = function(){
    obj.data += 1;
    console.log('data:', obj);
  };

  this.getData     = function() { return obj; };

}]);

app.controller('TestController', ['$scope', '$rootScope', '$filter', 'test',
                          function($scope,   $rootScope,   $filter,   test) {

  //test controller
  $scope.add = function(){
    test.add();
  };
  $scope.test = test;
  $scope.$watch('test.getData()', function(newVal){
    console.log('data changes into: ', newVal)
  });
}]);
Robin Timman
  • 489
  • 2
  • 7
  • 17
  • 1
    possible duplicate of [$watch an object in angular](http://stackoverflow.com/questions/19455501/watch-an-object-in-angular) – kvetis Nov 07 '14 at 12:08
  • 2
    I suggest you to write `function(){ return test.getData(); },` instead 'test.getData()'. By this way you can avoid bugs, because angular doesn't validate string definition. – Maxim Shoustin Nov 07 '14 at 12:19

2 Answers2

20

injecting whole services into a scope is not something I would do.

I would prefer to watch a function returning the value :

$scope.$watch(function() { return test.getData(); }, function(newVal) { 
    /* Do the stuff */
}, true);
Pierre Gayvallet
  • 2,933
  • 2
  • 23
  • 37
  • 4
    Actually this is the only way I was able to get the watch to work when watching an array instead of a function (e.g. test.data). – JD Smith Oct 15 '15 at 16:48
14

You need to pass true as the last parameter of the $watch function so that the equality check is angular.equals. Otherwise only reference equality is checked.

$scope.$watch('test.getData()', function(newVal){
  console.log('data changes into: ', newVal)
}, true);

Duplicate question: $watch an object

EDIT

As mentioned bellow, the code includes a bad practice – having a service referenced in $scope. It is not necessary to reference it in scope, since $watch also accepts a getter function as first argument. Clean solution uses this function to return the watched array as is in the answer below. $scope.$watch(function() { return test.getData(); } ...

To list a complete solution you could also use $watchCollection instead to solve the reference equality check problem.

Community
  • 1
  • 1
kvetis
  • 6,682
  • 1
  • 28
  • 48