287

I have a watch function in my AngularJS application.

$scope.$watch('quartzCrystal', function () {
   ...
}

However, after some condition (in my example, changing the page at my single-page application) I want to stop that watch (as like clearing timeout).

How can I do that?

John Slegers
  • 45,213
  • 22
  • 199
  • 169
kamaci
  • 72,915
  • 69
  • 228
  • 366

6 Answers6

530

$watch returns a deregistration function. Calling it would deregister the $watcher.

var listener = $scope.$watch("quartz", function () {});
// ...
listener(); // Would clear the watch
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Umur Kontacı
  • 35,403
  • 8
  • 73
  • 96
  • 25
    Do you know if it's a good practice to deregister all your listeners at the end of a controller lifecycle (like on a `$on('$destroy')`) or AngularJS will take care of them? thanks! – yorch Oct 02 '13 at 17:36
  • 84
    All watchers will be removed when the scope is destroyed, you don't need to manage those – Umur Kontacı Oct 02 '13 at 20:03
  • @UmurKontacı - do you have a source for your claim that when a scope is destroyed the watchers are removed? It does not appear to be part of the [`$destroy` function](https://github.com/angular/angular.js/blob/cceb455fb167571e26341ded6b595dafd4d92bc6/src/ng/rootScope.js#L693) – jelinson Feb 16 '14 at 18:44
  • 7
    You can see an interesting discussion here that explains the matter: https://github.com/angular/angular.js/issues/4574 Basically, if you assign a listener to the $rootScope, you have to unassign it your self, or it will persist through $scope changes. Watchers on $scope get destroyed with the $scope ($scopes are not singletons in Angular, and they get created and destroyed when needed). – Mladen Danic Mar 12 '14 at 09:46
  • 3
    But, what if i only want the watcher for checking if the value exists and then when it exists do some changes and then de register itself i already tried - var listen = $scope.$watch('mvIdentity.currentUser', function(currentUser) { test = 1; console.log("--> " + $scope.updateemail + " -- " + test); listen(); }); – Harshit Laddha Jun 22 '14 at 05:28
  • 4
    @UmurKontacı Actually deadman's comment is perfectly valid as your original comment is not correct for every case. – GFoley83 Jul 21 '14 at 22:08
  • 1
    Note: $scope.$$watchers contains all the watches on a particular scope. It is dangerous but you can manipulate them. Courtesy: https://coderwall.com/p/d_aisq – Sanket Sahu Oct 02 '14 at 10:14
  • 1
    Note: `$scope.$$watchersCount` helps a lot for debugging. – Ice-Blaze Nov 04 '15 at 14:31
49

scope.$watch returns a function that you can call and that will unregister the watch.

Something like:

var unbindWatch = $scope.$watch("myvariable", function() {
    //...
});

setTimeout(function() {
    unbindWatch();
}, 1000);
Anders Ekdahl
  • 22,685
  • 4
  • 70
  • 59
26

You can also clear the watch inside the callback if you want to clear it right after something happens. That way your $watch will stay active until used.

Like so...

var clearWatch = $scope.$watch('quartzCrystal', function( crystal ){
  if( isQuartz( crystal )){
    // do something special and then stop watching!
    clearWatch();
  }else{
    // maybe do something special but keep watching!
  } 
}
SoEzPz
  • 14,958
  • 8
  • 61
  • 64
4

Some time your $watch is calling dynamically and it will create its instances so you have to call deregistration function before your $watch function

if(myWatchFun)
  myWatchFun(); // it will destroy your previous $watch if any exist
myWatchFun = $scope.$watch("abc", function () {});
naCheex
  • 1,131
  • 3
  • 14
  • 34
4

If you have too much watchers and you need to clear all of them, you can push them into an array and destroy every $watch in a loop.

var watchers = [];
watchers.push( $scope.$watch('watch-xxx', function(newVal){
   //do something
}));    

for(var i = 0; i < watchers.length; ++i){
    if(typeof watchers[i] === 'function'){
        watchers[i]();
    }
}

watchers = [];
Danilo Cândido
  • 408
  • 1
  • 5
  • 18
Rewar
  • 74
  • 6
4

Ideally, every custom watch should be removed when you leave the scope.

It helps in better memory management and better app performance.

// call to $watch will return a de-register function
var listener = $scope.$watch(someVariableToWatch, function(....));

$scope.$on('$destroy', function() {
    listener(); // call the de-register function on scope destroy
});
Manish Kumar
  • 1,131
  • 15
  • 28