In angular if I register watch events dynamically (in my case in a for loop), the watch does not work. Please take a look at a fiddle. Any ideas?
var myApp = angular.module('myApp',[]);
function MyCtrl($scope, $parse) {
    // 1. binding watch inside loop (doesn't work):
    $scope.aaa = 1;
    $scope.bbb = 2;
    $scope.dependsOn = [
        function () { return $scope.aaa; },  
        function () { return $scope.bbb; }
    ];        
    for (var i = 0; i < $scope.dependsOn.length; i++) {        
        $scope.$watch(
            function () {
                return $scope.dependsOn[i];                    
            },
            function (newVal) {
                if (newVal !== undefined) {
                    console.log("doesn't work");
                }
            }
        );
    }    
    $scope.aaa = 5;
    $scope.bbb = 6;    
    // binding watch not inside loop (works):
    $scope.ccc = 1;
    $scope.ddd = 2;    
    $scope.dependsOn = [
        function () { return $scope.ccc; },
        function () { return $scope.ddd; }
    ];    
    $scope.$watch(
        function () {
            return $scope.dependsOn[0];                    
        },
        function (newVal) {
            if (newVal !== undefined) {
                console.log("works");
            }
        }
    );    
    $scope.$watch(
        function () {
            return $scope.dependsOn[1];                    
        },
        function (newVal) {
            if (newVal !== undefined) {
                console.log("works");
            }
        }
    );     
    $scope.ccc = 5;
    $scope.ddd = 6;      
}
fiddle
The problem you are experiencing is because you are capturing the variable i in a closure.  Then i gets incremented to the value 2 and drops out of the loop, each of your delegates will have 2 as their i value upon actually executing the delegate.
Demonstrates: http://jsfiddle.net/df6L0v8f/1/ (Adds:)
$scope.$watch(
     function () {
         console.log(i);
         return $scope.dependsOn[i];                    
     },
    function (newVal) {
         if (newVal !== undefined) {
              console.log("doesn't work");
         }
    }
);
You can fix this and the issue of variable hoisting by using a self calling closure to capture the value at the time of iteration and maintain that for your delegate.
http://jsfiddle.net/df6L0v8f/4/
for (var i = 0; i < $scope.dependsOn.length; i++) {        
     var watchDelegate = (function(itemDelegate){
          return function () {
              return itemDelegate;                    
          };
      })($scope.dependsOn[i]);
      $scope.$watch(
          watchDelegate,
          function (newVal) {
              if (newVal !== undefined) {
                  console.log(newVal());
              }
          }
      );
  }
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With