1

I want to trigger things ONLY when a variable changes its value. The aim is to use this variable as a flag to indicate that a database is ready to be used, and then to use the $watch to detect when this happens and continue with something else.

The simplified version of this would be the following:

<div ng-app="watchApp" ng-controller="watchCtrl">
    {{status}}
</div>

and

angular.module('watchApp', []).controller('watchCtrl', 
['$scope', 'myVariables', 
function($scope, myVariables) {
    $scope.status = myVariables.myVar;
    $scope.$watch(
        function() {return myVariables.myVar;},
        function(newVal, oldVal) {
            $scope.status = 'changed';
        }
    );
   setTimeout(function(){myVariables.myVar = 1;alert('ei');},1000);
}]);

angular.module('watchApp').factory('myVariables', 
['$window', '$q',
function($window, $q) {
    return {
        myVar: 0,
    }
}]);

http://jsfiddle.net/SQuVy/218/

So, the timeout should change the variable after 1 second, and then the watch should trigger the cascade and change the displayed message.

But it does not work. Why? Perhaps because within the Timeout I do not have access to the variable? Here the Timeout is to exemplify the problem, but it does not exist in my code. How could I do this?

Cheers, Gerard

2 Answers 2

2

Two changes. First, the $watch will fire the initial time it is set so you want to check that the values actually change:

if (newVal !== oldVal) {
   $scope.status = 'changed';
}

Second, you either need to inject $timeout as a service and use that instead of setTimeout, or use $scope.$apply in order to notify Angular of the changes:

setTimeout(function(){$scope.$apply(function() { 
        myVariables.myVar = 1;alert('ei');});},1000);

Here is your working fiddle: http://jsfiddle.net/jeremylikness/HU7Wn/

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

4 Comments

Thanks a lot. However, when I apply it to my code I get the error "$digest already in process". I have tried to simulate better what I have, check why it is not working here jsfiddle.net/HU7Wn/4
In your code the Processing.doIt is from inside a $scope so the $apply isn't needed. You also resolve the promise before you return it. This one is more realistic and works: jsfiddle.net/jeremylikness/HU7Wn/5
So I can see that your fiddle works if the timeout is active. But if you comment the timeout part then it does not work. For instance, compare and look at the alerts in jsfiddle.net/HU7Wn/7 versus jsfiddle.net/HU7Wn/8. Does it mean that I have to create an artificial delay in my code?
Somehow now my code works, but I cannot say what I've changed. Something I guess, and without the timeout, just the time that the funcions need to be completed is enough delay to change the value at a resolution that watch can detect. Thanks again :)
1

Its $scope.$watch not $scope.watch, rest is exactly same no change at all

Code

angular.module('watchApp', []).controller('watchCtrl', 
['$scope', 'myVariables', 
 function($scope, myVariables) {
    $scope.status = myVariables.myVar;
    $scope.$watch(
        function() {return myVariables.myVar;},
        function(newVal, oldVal) {
            $scope.status = 'changed';
        });

    setTimeout(function(){myVariables.myVar = 1;alert('ei');},1000);
}]);

DEMO

5 Comments

and you can simplify the first part of the watch to: $scope.$watch('status', function(...)); And just an advice - use $timeout instead of setTimeout
Yes, absolutely right :) Though, the $watch is triggered immediately and the status do not wait 1s to show 'changed'
@Gerard, What do you want, to show status to show after 1 second
I want to change the text in "status" only when the variable changes, which should happen after 1 second.
Yes but no, now it waits 5 seconds because the setTimeout tells it to do. What I want is that when the variable changes, then the message changes. I actually want the $watch to watch the variable and triggers the function when this variable is modified.

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.