Search code examples
angularjsangularjs-service

$watch not detecting changes in service variable


I am new to angularjs and I am facing this strange problem where $watch is not firing on change of a variable in service. I don't know where I have made a mistake.

Plunkr: Link to Plunkr

script.js file:

var app = angular.module("app", []);
app.factory("loggedInUser", [loggedInUser]);

function loggedInUser() {
  var currentLoggedInUser = undefined;
  setTimeout(function() {
    currentLoggedInUser = "Karthik";
    console.log("Updated user name");
  }, 3000);
  return {
    getLoggedInUser: function() {
      return currentLoggedInUser;
    }
  };
}

app.controller("ctrl", ["$scope", "loggedInUser", ctrl]);

function ctrl($scope, loggedInUser) {
  var vm = this;
  $scope.$watch(function() {
    return loggedInUser.getLoggedInUser();
  }, function() {
    vm.loggedInUserName = loggedInUser.getLoggedInUser();
    console.log("Inside Watch");
  },true);
} 

HTML:

<html>

  <head>
    <script src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js" data-require="[email protected]" data-semver="1.5.8"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body ng-app="app">
    <h1 ng-controller="ctrl as vm">
      Hello <span ng-bind="vm.loggedInUserName"></span>
    </h1>
  </body>

</html>

Solution

  • use $timeout instead of setTimeout ? .. cause it need$scope.$apply (outside angular event) .. $timeout is a angular wrapping for setTimeout .. something like:

     // Code goes here
    
    var app = angular.module("app", []);
    app.factory("loggedInUser", ["$timeout", loggedInUser]);
    
    function loggedInUser($timeout) {
      var currentLoggedInUser;
       $timeout(function() {
        currentLoggedInUser = "Karthik";
        console.log("Updated user name");
      }, 3000);
      return {
        getLoggedInUser: function() {
    
          return currentLoggedInUser;
        }
      };
    }
    
    app.controller("ctrl", ["$scope", "loggedInUser", ctrl]);
    
    function ctrl($scope, loggedInUser) {
      var vm = this;
      $scope.$watch(function() {
        return loggedInUser.getLoggedInUser();
      }, function() {
        vm.loggedInUserName = loggedInUser.getLoggedInUser();
        console.log("Inside Watch");
      },true);
    }
    

    BUT .. IF YOU WANT TO USE instead SetTimeout function:

      // Code goes here
    
    var app = angular.module("app", []);
    app.factory("loggedInUser", ["$rootScope",loggedInUser]);
    
    function loggedInUser($rootScope) {
      var currentLoggedInUser = undefined;
      setTimeout(function() {
        $rootScope.$apply(function(){
        currentLoggedInUser = "Karthik";
        console.log("Updated user name");
        });
      }, 3000);
      return {
        getLoggedInUser: function() {
          return currentLoggedInUser;
        }
      };
    }
    
    app.controller("ctrl", ["$scope", "loggedInUser", ctrl]);
    
    function ctrl($scope, loggedInUser) {
      var vm = this;
      $scope.$watch(function() {
        return loggedInUser.getLoggedInUser();
      }, function() {
        vm.loggedInUserName = loggedInUser.getLoggedInUser();
        console.log("Inside Watch");
      },true);
    }