0

We have the following directive:

app.directive("counterWidget",function(){
  return{
    restrict:"E",
    scope:{
      startnumber: '=',
      resetter: '='
    },
    link:function(scope,elem,attr){
        scope.f =  attr.startnumber;
        scope.add = function(){             
            scope.f++
        }
        scope.remove = function(){
            scope.f--
        }
        scope.reset = function(){
            scope.f = attr.startnumber
            scope.$parent.triggerReset()
        }
        scope.$watch(function(attr) {
          return attr.resetter
        },
        function(newVal) {
          if (newVal === true) {
            scope.f = attr.startnumber;
          }
        })

    },
    template:"<button ng-click='add()'>more</button>"+
             "{{f}}"+
             "<button ng-click='remove()'>less</button>&nbsp"+
             "<button ng-click='reset()'>reset</button><br><br>"
    }

  })

In this directive there is a watch function, which watches the resetter attribute for changes. That attribute is triggered by this function in the controller:

$scope.triggerReset = function () {
    $scope.reset = true;
    console.log('reset')
    $timeout(function() {
      $scope.reset = false; 
    },100)
}

The question came up - can $watch 'miss'? If the timeout is too short, or...I don't know...something else causes it to hangup for some reason, can it fail to catch the toggle?

I have the following demo: Plunker

I set the timeout to 1ms, and even removed it all together and it still resets fine. But can some situation arise where a $watch would become unreliable?

tpie
  • 6,021
  • 3
  • 22
  • 41

1 Answers1

0

No. You can even set it to 0ms, and it will still catch.

$timeout will always cause the code internal to its function to run in a different $digest cycle from the current one.

$evalAsync, on the other hand, may cause a miss depending on the circumstances.

See this answer for more details: https://stackoverflow.com/a/16066461/624590

EDIT: I missed an edge-case to this where a third parameter is passed to the $timeout function. If you call $timeout(fn, 50, false) (notice the false at the end), it will skip the $apply step and allow you to "miss" the change. This is based on the $timeout source code: https://github.com/angular/angular.js/blob/master/src/ng/timeout.js#L64

Community
  • 1
  • 1
DRobinson
  • 4,441
  • 22
  • 31
  • Yes, that makes sense to me. Watchers are fired up on every digest cycle. – tpie Apr 23 '15 at 13:08
  • Moreover, you don't have to set it to anything but 0ms in such case. – Estus Flask Apr 23 '15 at 13:10
  • Yes, when I said I removed it all together, that is what I meant - $timeout(function() {}) – tpie Apr 23 '15 at 13:13
  • 1
    Yep, you don't need to explicitly say 0. I tend to, though, so that it's obvious that the 0 was intentional and not a mistake when the code's being maintained later. – DRobinson Apr 23 '15 at 13:15