2

Performing For..Loops or While..Loops does not update the $scope variable. I'm trying to show the progress as loops are incremented.

I have read (http://jimhoskins.com/2012/12/17/angularjs-and-apply.html) that we need to use $apply to force updates if changes are not detected via an event or a promise such ng-click() event or $http call.

I have tried forcing the update using $apply but this does not seem to change anything.

I have tried using $timeout but again the tests were negative.

In the code below I have tried three different tests. Initially I tried a For..loop, then I tried a while..loop and then a while..loop with a $apply. These tests are independent of one another and I have included all three just to show you what variations I've tried.

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

myApp.controller('CounterController', ['$scope', '$timeout', function($scope, $timeout) {


  $scope.counterMax = 5000;


  $scope.startCounter = function() {
    $scope.progress = 0;
    $scope.progress2 = 0;
    $scope.progress3 = 0;
    // for loop $scope test
    for (i = 0; i <= $scope.counterMax; i++) {

      $timeout(function() {
        $scope.progress = i;
      }, 500);
    }

    // while loop $scope test
    var x = 0;
    try {
      while (x < $scope.counterMax) {
        $timeout(function() {
          $scope.progress2 = x;
        }, 2);
        x++;

      }
    } catch (error) {
      console.log("Error: " + error);
    }



    // while loop $scope test with $apply
    x = 0;
    try {
      while (x < $scope.counterMax) {
        $timeout(function() {
          $scope.$apply(function() {
            $scope.progress3 = x;
          });
        }, 2000);
        x++;

      }
    } catch (error) {
      console.log("Error: " + error);
    }
  }

  $scope.startCounter();
}]);

The view

<div ng-controller="CounterController">
      <p>
        Depending on the value for the Counter Max, a loop will be made from zero to 
        the Counter Max value. 
        <br />
        The value in the Progress Indicators should increment gradually until the Counter Max value is reached.
        <br />
        Currently this is not happening. The Progress Indicators are only updated at the 
        end of the loop.
      </p>
      <p>
        Counter Max: <input type="text" ng-model="counterMax" ng-keyup="startCounter()"/>
      </p>
      <p>(for loop $scope test)<br />
      Progress Indicator 1: {{progress}}</p>

      <p>(while loop $scope test)<br />
      Progress Indicator 2: {{progress2}}</p>

      <p>(while loop $scope test with $apply)<br />
      Progress Indicator 3: {{progress3}}</p>
    </div>

You can see the tests I've made here on plnkr: http://plnkr.co/edit/Nl3GMy0DJNJ53PFObAq1?p=preview

Deakus
  • 51
  • 4
  • Possible duplicate of [setTimeout in for-loop does not print consecutive values](http://stackoverflow.com/questions/5226285/settimeout-in-for-loop-does-not-print-consecutive-values) – Dan Prince Nov 19 '15 at 12:45

1 Answers1

0

The loop that registers the timeouts will always be very fast, and since the delays passed to $timeout in each iteration are identical, they will fire simultaneously and the view will appear to update just once.

If you want the number to gradually increase in the view, the delay passed to $timeout needs to be incremented, like in the example below. Also, since the value of i is changed permanently with each iteration, make sure to increment the progress variable based on its current value.

for (i = 0; i <= $scope.counterMax; i++) {
  $timeout(function() {
    $scope.progress++;
  }, i);
}
fredrikekelund
  • 2,007
  • 2
  • 21
  • 33
  • Thanks for your reply. Your suggestion doesn't seem to change anything. I think your're missing the point that the three loops are just different ways I've tried to find an answer to the problem. If you play with the plnkr example you'll see that increasing the timeout doesn't change anything, the problem still exists in that the view is only updated after the loop is complete. – Deakus Nov 19 '15 at 13:07
  • I had to update my example, because I initially missed the fact that the value of i would change permanently after the loop was over, but using the updated for loop as a replacement for the first loop in your Plunkr example actually does update the view once per fired timeout when I test it. Are you still having trouble with the first loop? – fredrikekelund Nov 19 '15 at 13:10