1

I have a jsfiddle for this issue. https://jsfiddle.net/uvtw5kp1/4/

$scope.Dropdown = {
  open: false,
  searchValue: "",

  timer: null,

  hideIt: function() {

    this.timer = $timeout(function() {
      alert("timeout happened the value will not change");
      this.open = false;
    }, 50);
  },
  hideItNotimer: function() {

    this.open = false;

  },
  showIt: function() {
    $timeout.cancel(this.timer);
    this.open = true;
  }
};

When I call Dropdown.hideItNotimer() on ng-mouseout it has no problem, but when I call Dropdown.hideIt() the variable is not set. I have added an alert to ensure the timer is working, and I've tried doing a scope.apply after. What does work is having a scope level function called within the timer:

like this:

 $scope.setDropdownHidden = function(){
   $scope.Dropdown.open = false;
 }

and call that from within the timeout it works, but I want to avoid this if I can.

What am I missing?

Pop-A-Stash
  • 6,572
  • 5
  • 28
  • 54
NetHawk
  • 1,392
  • 1
  • 15
  • 33

2 Answers2

2

In your timeout function, this does not refer to the Dropdown object, it instead probably refers to the window object. In javascript this always refers to whichever object the function was invoked with, not the object in which it was defined. When $timeout invokes your callback function it will do so with something other than your Dropdown object since it doesn't know about that object.

Related: Javascript closures and this

You need to either capture the value of this in the parent function as a closure variable or bind your callback function to the Dropdown object using angular.bind

kicken
  • 2,122
  • 14
  • 17
1

Timeout has its own scope since it is a closure, so the $scope.open = false is not updating your controller $scope.open variable, you should avoid using timeout for to update scope variables. You should bind the global scope with using bind as -

hideIt: function() {
  this.timer = $timeout(function() {
        this.open = false;
      }.bind(this), 50);
}
Abhi
  • 60
  • 9