$watch on rootscope not working, angular

Problem

I have a button which toggles admin and client mode. I've put it in on the rootscope so I can access it everywhere.

I'm using the angular-ui directive for toggling.

I've put a watch on this model. But nothing is happening. Any idea what can be wrong?

.run(['$rootScope', '$state', '$stateParams', '$location',
     function ($rootScope, $state, $stateParams, $location) {

         $rootScope.projectMode = 'Client';

         $rootScope.$watch('projectMode', function(){
             var path = $location.path();
             alert("fire") //Only fire ones when the app starts
             if($rootScope.projectMode === 'Client'){
                 var current = 'client'
                 var replace = 'admin'
             } else {
                 var current = 'admin'
                 var replace = 'client'
             }
             var newUrl = path.replace(current, replace)
             $location.url(newUrl);
         })

    }])

Here's my view.

<div class="btn-group">
  <button type="button" class="btn btn-default"  ng-model="projectMode" btn-radio="'Client'">Klient</button>
  <button type="button" class="btn btn-default"  ng-model="projectMode" btn-radio="'Admin'">Admin</button>
</div>

btn-radio is the angular-ui directive for toggling.

I've checked that the $rootScope.projectMode is changing. So it must be something wrong with the $watch.

Problem courtesy of: Per Ström

Solution

The real problem is that the projectMode in your view is not the same projectMode on the $rootScope. This is a common problem people have in Angular.

Scopes in Angular are prototypical. If a property isn't found in the current scope, then it looks for the property with the same name in that scope's parent, and so on until it reaches the $rootScope. So, when your view initializes, it may appear that projectMode is whatever you initialized it to on $rootScope.

However, as soon as you change the value of projectMode, it creates a new value on the controller's scope named projectMode, which is not the same as $rootScope.projectMode. So, it makes sense that your $watch isn't fired... The $rootScope value isn't changing, only the controller scope's value is changing.

If you'd like to fix it, simply change projectMode to $root.projectMode everywhere in your HTML. ($root inside HTML is how you reference $rootScope.)

Solution courtesy of: Lukas

Discussion

The Trick won't work for me - i had to apply the rootScope after changing the variable:

    //Change rootScope-Varible to break
    $rootScope.dbsynchstat = "break";
    //Apply to Scope
    $rootScope.$apply();

After that i can do something like that in any Controller i want to:

$rootScope.$watch('dbsynchstat', function(){
    if($rootScope.dbsynchstat == 'break'){
        init();
    }   
}, true);

Do not forget to add the $rootScope to you're controller.

Discussion courtesy of: HolgerT

There's a little known third option for the $watch where it checks for object equality rather than object reference. Set that to true. So try this,

$rootScope.$watch('projectMode', function(){
 ...your stuff here
}, true);
Discussion courtesy of: dheerajmanju1

Try this - also I would recommend running JSLint

.run(['$rootScope', '$state', '$stateParams', '$location',
    function ($rootScope,   $state,   $stateParams, $location) {

      $rootScope.projectMode = 'Client';
      var current = '';
      var replace = '';
      var newUrl = '';
      var path = '';

      $rootScope.$watch('projectMode', function(){
        path = $location.path();
        if($rootScope.projectMode === 'Client'){
          current = 'client';
          replace = 'admin';
        }else{
          current = 'client';
          replace = 'admin';
        }
        newUrl = path.replace(current, replace);
        $location.url(newUrl);
      })

    }])

I would also suggest using Angular's pub sub pattern and have a service watch for messages you could try using $rootScope.$broadcast and in your service $rootScope.$on and then change you location

Discussion courtesy of: Mark-Sullivan

This recipe can be found in it's original form on Stack Over Flow.