AngularJS trigger and watch object value change in service from controller

54,253

Try to write $watch by this way:

myApp.controller('MyCtrl', function($scope, myService) {


    $scope.setFTag = function() {
       myService.setFalseTag();
    };        

    $scope.$watch(function () {
       return myService.tags;
     },                       
      function(newVal, oldVal) {
        /*...*/
    }, true);

});

Demo Fiddle

[EDIT]

Sometimes this way will not work especially if service has been updated from 3d party.

To make it work we must help to angular to fire digest cycle.

Here is an example:

On service side when we want update tags value write something like:

if($rootScope.$root.$$phase != '$apply' && $rootScope.$root.$$phase != '$digest'){
   $rootScope.$apply(function() {
     self.tags = true;
   });
 }
 else {
   self.tags = true;
  }
Share:
54,253
sathishvj
Author by

sathishvj

Updated on December 07, 2020

Comments

  • sathishvj
    sathishvj over 3 years

    I'm trying to watch for changes in a service from a controller. I tried various things based on many qns here on stackoverflow, but I've been unable to make it work.

    html:

    <div ng-app="myApp">
        <div ng-controller="MyCtrl">
            <div ng-click="setFTag()">Click Me</div>
        </div> 
    </div>
    

    javascript:

    var myApp = angular.module('myApp',[]);
    
    myApp.service('myService', function() {
        this.tags = {
            a: true,
            b: true
        };
    
    
        this.setFalseTag = function() {
            alert("Within myService->setFalseTag");
            this.tags.a = false;
            this.tags.b = false;
    
            //how do I get the watch in MyCtrl to be triggered?
        };
    });
    
    
    myApp.controller('MyCtrl', function($scope, myService) {
    
        $scope.setFTag = function() {
            alert("Within MyCtrl->setFTag");
            myService.setFalseTag();
        };        
    
        $scope.$watch(myService.tags, function(newVal, oldVal) {
            alert("Inside watch");
            console.log(newVal);
            console.log(oldVal);
        }, true);
    
    });
    

    How do I get the watch to trigger in the Controller?

    jsfiddle

  • joseym
    joseym about 10 years
    I had no idea you could use watch in this way. This is a game changer. So much win.
  • Maxim Shoustin
    Maxim Shoustin almost 10 years
    for me this way is better because you avoid spelling mistakes with variables.
  • Maxim Shoustin
    Maxim Shoustin almost 10 years
    @Phill I only added other test case: if you use for example Cordova plugin thats out of angular scope, the watcher doesn't work. People might copy/paste this example and will be surprised why it doesn't work. So I try to cover different cases
  • lvarayut
    lvarayut over 9 years
    Can you explain a little bit why we have to use the return function? It worked perfectly but I don't really get it.
  • CodyBugstein
    CodyBugstein about 9 years
    Why is there no return statement in the service? How does that work?
  • Azadrum
    Azadrum over 8 years
    I had to use $rootScope.$apply to trigger a watched variable inside my controller after it is being changed inside a directive.