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.

1
  • Sorry, I was wrong with my example. I am going to research it more and answer again :) Commented Nov 17, 2013 at 15:22

1 Answer 1

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
            }
        }
    }
});
Sign up to request clarification or add additional context in comments.

2 Comments

I'm still not clear why setTimeout wouldn't work in "myDirective" though.
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 and Angular Is Slow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.