29

I know you can unbind a $watch like this:

var listener = $scope.$watch("tag", function () {});
// ...
listener(); // would clear the watch

but can you unbind the watch within the watch function declaration. So after the watch gets executed once, it unbinds itself? Something like:

$scope.$watch("tag", function () {
    unbindme()
});
Michael
  • 7,087
  • 21
  • 52
  • 81

5 Answers5

60

you can just do it the same way you already do, call the "deregistration" inside your function:

var unbind = $scope.$watch("tag", function () {
    // ...
    unbind();
});
Kris Ivanov
  • 10,476
  • 1
  • 24
  • 35
  • 19
    `listener` would be better named `unbind`. – SavoryBytes May 18 '15 at 15:38
  • @daniellmb anything wrong if I call `listener()` once more ? I have a piece of code where the `listener()` is executed only if a condition is satisfied. So is ther any problem if I call the unbinding function again, outside ( maybe inside `scope.$on('destroy')` ), just to make sure ? – Dane Nov 16 '17 at 05:42
  • 1
    @Dane you can call it as many times as you wish, easy to test too – Kris Ivanov Nov 17 '17 at 18:52
10

Because tag is an expression, you can use one-time binding to unbind once the value was received:

$scope.$watch("::tag", function () {});

angular
.module('app', [])
.controller('example', function($scope, $interval) {
  $scope.tag = undefined
  $scope.$watch('::tag', function(tag) {
    $scope.tagAsSeen = tag
  })
  $interval(function() {
    $scope.tag = angular.isDefined($scope.tag) ? $scope.tag + 1 : 1
  }, 1000)
})
angular.bootstrap(document, ['app'])
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body ng-controller="example">
Tag: {{tag}}
<br>
Watch once result: {{tagAsSeen}}
</body>
</html>
1

bindonce directive maybe what you need.

https://github.com/Pasvaz/bindonce

Wei Liu
  • 43
  • 1
  • 4
0
var unbindMe=$scope.$watch('tag',function(newValue){
    if(newValue){
       unbindMe()
    }
})
Arun Redhu
  • 1,584
  • 12
  • 16
0

Just like a similar question, a slight improvement to @Kris' answer will get you something more sleek and re-usable throughout the project.

.run(function($rootScope) {
    $rootScope.see = function(v, func) {
        var unbind = this.$watch(v, function() {
            unbind();
            func.apply(this, arguments);
        });
    };
})

Now thanks to scope prototypical inheritance you can simply go

$scope.see('tag', function() {
    //your code
});

And not worry about unbinding at all.

Hashbrown
  • 12,091
  • 8
  • 72
  • 95