1

I'm new to AngularJS. I'm looking at using the $timeout service. I've read that one of the reasons for using $timeout over the JavaScript setTimeout function is because changes to variables in the $scope don't get updated in the UI until $scope.$apply is called. While that's the word, I'm unable to confirm this with actual code. I've written the following:

index.html

<div ng-app="myApp">
  <div ng-controller="myController">
    <div>AngularJS Count: {{total1}}</div>
    <br />

    <div>setTimeout Count: {{total2}}</div>
    <br />

    <button ng-click="start()">start</button>
  </div>
</div>

myController.js

var app = angular.module("myApp", []);
function myController($scope, $timeout) {
  $scope.total1 = 0;
  $scope.total2 = 0;

  $scope.isStarted = false;
  $scope.toggle = function() {
    if (!$scope.isStarted) {
      $scope.isStarted = true;

      $timeout(ngUpdate, 1000);      
      setTimeout(jsUpdate, 1000);
    }    
  };  

  function ngUpdate() {
      $scope.total1 = $scope.total1 + 1;
  }

  function jsUpdate() {
      $scope.total2 = $scope.total2 + 1;
  }
}

In this code sample, the changes to the variables on the $scope are updated in the UI. I'm trying to see a scenario, in code, where a change via the setTimeout function doesn't update the UI until $scope.$apply is called. Am I misunderstanding? Or was a change made to the AngularJS framework that makes the original assertion out-of-date.

JQuery Mobile
  • 6,221
  • 24
  • 81
  • 134

1 Answers1

0

Since, you are calling setTimeout from inside $scope.toggle, this code is already executing in the context of a $digest cycle. So, there is no need to call $apply.

$timeout will test if it is in a $digest and then only call $apply if it needs to. This is very useful when building directives that bind to events that are happening outside of the angular context.

Here is a directive scenario when $timeout is needed:

app.directive('myDirective', function() {

    return {
        link: function(scope, element) {

            element.bind('click', function() {

                // $timeout is needed here because the 'click' event is outside angular
            }
        }
    }
});
Davin Tryon
  • 66,517
  • 15
  • 143
  • 132
  • I'm still not clear why setTimeout wouldn't work in "myDirective" though. – JQuery Mobile Nov 17 '13 at 16:53
  • What are you unclear on? `setTimeout` will work, But the angular `$watch` queue is only triggered by angular. If you are making changes to scoped properties, and you are outside of angular, you need to tell angular to take another look. If you haven't yet, check out [conceptual overview](http://docs.angularjs.org/guide/concepts) and [Angular Is Slow](http://hueypetersen.com/posts/2013/06/17/angular_is_slow/). – Davin Tryon Nov 17 '13 at 22:31