0

I am trying to watch a simple object on $scope, but I am confused as to why the following always outputs state:{value} for both the country and state select elements.

angular.module('app').controller('FiltersCtrl', ['$scope', 'filterRepo', function ($scope, filterRepo) {

    $scope.data = {
        lookups: {
            countries: [
                { id: 1, name: 'USA' },
                { id: 2, name: 'Canada' },
                { id: 3, name: 'Mexico' }
            ],
            states: [
                { id: 1, name: 'Oregon' },
                { id: 2, name: 'Texas' },
                { id: 3, name: 'Iowa' }
            ]
        }
    };

    $scope.query = {
        filter: {
            country: 1,
            state: 1
        }
    };

    for (var item in $scope.query.filter) {
        $scope.$watch('query.filter.' + item, function (newValue, oldValue) {
            if (newValue !== oldValue) {
                console.log(item + ' : ' + newValue);
            }
        }, false);
    }

}]);
4
  • 2
    You cannot use item safely inside the $watch callback, as its value will have changed to the last possible key (state) when the callback is run. Commented Jun 21, 2014 at 17:20
  • fiddle-ized jsfiddle.net/E62VE Commented Jun 21, 2014 at 17:21
  • @still_learning So how do I get a reference to the object that has changed? Commented Jun 21, 2014 at 17:22
  • @Sam use angular.forEach docs.angularjs.org/api/ng/function/angular.forEach Commented Jun 21, 2014 at 17:27

1 Answer 1

2

To expand on the comment from @still_learning above, only Functions have scope, meaning that the callbacks to your $watch statements are using the item variable you declared in the"parent" function. However, by the time these $watch callbacks are invoked/called, the for loop has already updated their values. There's an item about this in EffectiveJs (Item 13).

A great answer is to use the power of function closures via .forEach. Two downsides:

  1. Only for Arrays
  2. Only in the latest browsers

Angular provides a very convenient method to address both of these concerns in angular.forEach.

All this might sound rough :) but have a look at it in action in fiddle: http://jsfiddle.net/E62VE/3/

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.