Sassa
Sassa

Reputation: 159

AngularJS - triggering $watch/$observe listeners

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,

Upvotes: 1

Views: 2928

Answers (2)

Andriy Horen
Andriy Horen

Reputation: 2940

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

Upvotes: 1

Endre Simo
Endre Simo

Reputation: 11551

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
});

Upvotes: 0

Related Questions