78

i'm trying to figure out how Angular works and am having trouble getting my view to update when the model changes..

HTML

<div ng-app="test">  
        <p ng-controller="TestCtrl">  
            {{testValue}}  
        </p>  
    </div>

JS

var app = angular.module('test', []);

    app.controller('TestCtrl', function ($scope) {
       $scope.testValue = 0;

        setInterval(function() {
            console.log($scope.testValue++);
        }, 500);
    });

http://jsfiddle.net/N2G7z/

any ideas?

3
  • 4
    apart from below answer if you still want to use settimeout you have to use scope.$apply() Commented Nov 19, 2013 at 11:21
  • 6
    $scope.$apply() is what i need. the model in the project i'm working on is updated after user interaction. i'm not actually using a timeout or an interval but it's good to know how to use them with angular in the future. thanks for the answers! Commented Nov 19, 2013 at 12:00
  • Here is an interesting article in which you will more informations about the $digest cycles sitepoint.com/understanding-angulars-apply-digest Commented Mar 2, 2015 at 13:38

4 Answers 4

126

As Ajay beniwal mentioned above you need to use Apply to start digestion.

var app = angular.module('test', []);

app.controller('TestCtrl', function ($scope) {
   $scope.testValue = 0;

    setInterval(function() {
        console.log($scope.testValue++);
        $scope.$apply() 
    }, 500);
});
Sign up to request clarification or add additional context in comments.

5 Comments

Diego Vieira's answer is better. Rule of thumb would be: whenever possible, use Angular's providers/services, they do the apply by themselves.
At time I wrote that comment there were no any $intervals Its just wrapper to setInterval btw. also its not so save how it looks: Read more: docs.angularjs.org/api/ng/service/$interval
that's a hack, angular has its own timers, $interval should be used instead to update watchers
Read my comments above
This method is not safe to use because, it will continue to update model for the given interval...
37

Just use $interval

Here is your code modified. http://plnkr.co/edit/m7psQ5rwx4w1yAwAFdyr?p=preview

var app = angular.module('test', []);

app.controller('TestCtrl', function ($scope, $interval) {
   $scope.testValue = 0;

    $interval(function() {
        $scope.testValue++;
    }, 500);
});

Comments

30

setTimout executes outside of angular. You need to use $timeout service for this to work:

var app = angular.module('test', []);

    app.controller('TestCtrl', function ($scope, $timeout) {
       $scope.testValue = 0;

        $timeout(function() {
            console.log($scope.testValue++);
        }, 500);
    });

The reason is that two-way binding in angular uses dirty checking. This is a good article to read about angular's dirty checking. $scope.$apply() kicks off a $digest cycle. This will apply the binding. $timeout handles the $apply for you so it is the recommended service to use when using timeouts.

Essentially, binding happens during the $digest cycle (if the value is seen to be different).

Comments

8

Do not use $scope.$apply() angular already uses it and it can result in this error

$rootScope:inprog Action Already In Progress

if you use twice, use $timeout or interval

Comments

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.