Xenology
Xenology

Reputation: 2452

$scope.$watch does not trigger when property updates

Here is the watcher statement:

$scope.$watch($scope.currentStep , function(newVal , oldVal){
    console.log('Watch: ' ,$scope.currentStep , newVal , oldVal);
});

And this is the only code that changes the currentStep property, these functions are triggered on button clicks from the browser:

$scope.next = function(valid , event){
    event.preventDefault();

    if(valid){
        $scope.error = false;

         $scope.validate();

        if($scope.currentStep < $scope.totalSteps && !$scope.error){
            $scope.previousStep = $scope.steps.indexOf(true);
            $scope.currentStep = $scope.steps.indexOf(true) + 1;

            $scope.steps[$scope.previousStep] = false;
            $scope.steps[$scope.currentStep] = true;                       
        }
    }
    else {
        $scope.error = true;
        $scope.errorText ="Please fix your mistakes";
    }
}

$scope.prev = function(){
    $scope.error = false;
    $scope.final = false;
    $scope.lastPush --;

    $scope.previousStep = $scope.steps.indexOf(true);
    $scope.currentStep = $scope.steps.indexOf(true) - 1;

    $scope.steps[$scope.previousStep] = false;
    $scope.steps[$scope.currentStep] = true;            
}

What I can't understand is no matter that I do the watch only fires on the initialization of the variable. When currentStep updates the watch misses it. I've tried including the third argument with watch to force the watcher to compare by equality and not reference but that doesn't fix the issue. What am I missing here?

Upvotes: 0

Views: 311

Answers (2)

potatosalad
potatosalad

Reputation: 4887

Your $watch expression must be a String or a Function according to the $rootScope.$watch documentation.

Either of the following should work:

// String
$scope.$watch('currentStep', function(newVal, oldVal) {
    console.log('Watch: (current) %o (new) %o (old) %o', $scope.currentStep, newVal, oldVal);
});

// Function
$scope.$watch(function() {
    return $scope.currentStep;
}, function(newVal, oldVal) {
    console.log('Watch: (current) %o (new) %o (old) %o', $scope.currentStep, newVal, oldVal);
});

Upvotes: 4

Marc Kline
Marc Kline

Reputation: 9409

The first argument of $watch takes an expression or a function:

$scope.$watch('currentStep' , function(newVal , oldVal){
    console.log('Watch: ' ,$scope.currentStep , newVal , oldVal);
});

Yes, you could use a function

$scope.$watch(function(){ return $scope.currentStep } , function(newVal , oldVal){
    console.log('Watch: ' ,$scope.currentStep , newVal , oldVal);
});

but that is obviously more verbose and less desirable.

$watch docs

Upvotes: 3

Related Questions