3

I am having trouble with using $scope.$watch on some angular variables that I have in the scope of my project. I've made a sample jsfiddle to illustrate the issue.

Basically, I can $scope.$watch any model within the ng-switch as long as it is an object. If it is a string, it will not fire the watch expression, and will not be changed outside of the scope of the ng-switch area. Does Angular copy the original string instead of passing it by reference, like the object?

I'm using an ng-repeat over some elements -- here is some of my code:

<div ng-switch="key">

          <div ng-switch-when="deal_id">
              DEALID: <input type="text" ng-model="dealIdModel"/> -- {{dealIdModel}}
          </div>
          <div ng-switch-when="thing_id">
              THING: <input type="text" ng-model="thingIdModel.test"/> -- {{thingIdModel.test}}
          </div>
          <div ng-switch-default>
              DEFAULT: <input type="text" placeholder="email" ng-model="items.params.email"/> -- {{items.params.email}}
          </div>

        </div>

And the JS:

$scope.items = {
        "statusCode":"ACTIVE",
        "params":{
          "deal_id":"",
          "thing_id":"",
            "email":"Change me! I will get called"
        }
    };

    $scope.dealIdModel = "I won't change outside of the loop or get called.";
    $scope.thingIdModel = {test:'Change me! So will I!'};

    $scope.$watch('items.params.email', function (now, then, scope) {
        console.log('email change', now, then);
    });

    $scope.$watch('thingIdModel.test', function(now, then, scope) {
       console.log('changed the thing', now, then);   
    });

    $scope.$watch('dealIdModel', function(now, then, scope) {
        console.log('dealID changed:', now, then); 
    });

1 Answers1

3

This has to do with child scope being created by ng-repeat. Since a new scope is created, if you set a plain variable on the child scope you are changing the reference there, but not in the parent. When you use an object, the parent maintains the reference to the object and only the inner part changes.

This is the same problem as when you hear "always put a dot in your ng-model"

Much more detailed info here: https://github.com/angular/angular.js/wiki/Understanding-Scopes

Austin Greco
  • 32,997
  • 6
  • 55
  • 59
  • This is the right answer. Always use $scope.someObj.someProp instead of just $scope.someProp to avoid variable shadowing in inner scopes. – tandrewnichols Apr 16 '15 at 18:04
  • I feel sheepish... I'm newer to Angular, and that video (and write-up) were great. Good to know the 'always put a dot in your ng-model'. – Nicholaus Chipping Apr 16 '15 at 18:08