1

I would like to fire all $watch/$observe listeners even if watched/observed value didn't change. This way I could provide a "testing only" feature to refresh current page/view without user interaction. I've tried to call $apply/$digest but that didn't worked:

$timeout(function(){
    $scope.$apply();
});

$timeout(function(){
    $scope.$digest();
});

Is there any other way to do it?

Best Regards,

2 Answers 2

1

Executing $scope.$apply() will trigger digest cycle as it internally calls $digest, below is example of manual change.

number variable won't get bound as timeout brings it out of angulars scope.

setTimeout(function () { 
    $scope.number = Math.random(); 
});

however you can "force" it to show up by manually applying scope changes:

setInterval(function () {
    $scope.$apply(); 
}, 100);

Demos: No change / Change with manual updates

This will not trigger watchers though. From $digest implementation, it checks if value has changed since the last watch evaluation and will run callback only if it did.

if ((value = watch.get(current)) !== (last = watch.last) ... [rootScope.js]

Therefore you will need somehow change value of the last execution and it's possible to do via $$watchers object on the scope:

$scope.digest = function () {
    setTimeout(function () {
        angular.forEach($scope.$$watchers, function (w) {
            w.last.value = Math.random();
        });

        $scope.$apply();
    });
}

DEMO

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

8 Comments

OK, here is a plnkr with example: plnkr.co/edit/vDjIdGER66Fo2g6qCsDo?p=preview After user selects option, directive logs chosen option to console (via $observe), now, when user clicks on Refresh link, directive should log the same option.
Please check my updated answer, $scope.$apply() will trigger digest cycle and watchers will be re-evaluated however their callbacks get called only if watch expression value has changed since last execution. Not sure how to trigger them
What about temporal change of all watched values and then bringing them back?
Well it would work as a hack e.g. adding random property - jsfiddle.net/5b80t15k/2, there still should be better solution
And yes setInterval vs setTimeout has nothing to do with your problem, will update my answer.
|
0

How about to use the $emit function then capture that event with $on function?

Within an $emit() event function call, the event bubbles up from the child scope to the parent scope. All of the scopes above the scope that fires the event will receive notification about the event. We use $emit() when we want to communicate changes of state from within our app to the rest of the application.

_.bind($scope.$emit, $scope, 'myCustomEvent');

then on the capture phase:

$scope.$on('myCustomEvent', function() {                            
   // do something
});

1 Comment

Unfortunately, I cannot add custom events. Basically I need to add global refresh button/link without any code changes. Thats why I thought about triggering $watch/$observe. Here is a plnkr: plnkr.co/edit/vDjIdGER66Fo2g6qCsDo?p=preview with sample code.

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.