0

I found questions similar to this , but most of them ended up being about ng-repeat or something similar, which is not what I am after here.

In my case I am trying to loop through an array of messages to display one message at a time in the view. Here is my view:

<div id="centerWrap" ng-init="looptyloop()">
<p>{{centerWrapMessage[loop.loop]}}</p>
</div>

My controller has both $scope.centerWrapMessage and $scope.loop.

My controller is here:

$scope.centerWrapMessage = ["Click your category and then click your bread for more information.","If you intend to ship your order, please select a gift box","To add an item to your cart, hit the cart button"],
    $scope.loop = {
        loop: 0
    },
    $scope.looptyloop = function() {

    var i = 0;                    
function myLoop () {           
   setTimeout(function () {   
     i++; 
     $scope.loop.loop = i;
     if (i == $scope.centerWrapMessage.length - 1){
     i = -1;
     }
      if (i < $scope.centerWrapMessage.length) {            
         myLoop();             
      }                        
   }, 2222)
}

myLoop();        

},  

I can see in the console log (when I put it in) that the $scope.loop.loop is looping through like I want, but it never changes in the view. Why is this?

Thank you!

2 Answers 2

3

As your myLoop function is outside angular world so whenever you changes $scope object from outside, you need to call digest cycle explicitly i.e. $scope.$apply does for you. Also there are alternatives to do the same like you can use $timeout or $scope.$applyAsync i.e. newly introduce in Angular 1.3.

Using $scope.$apply() or $scope.$applyAsync

function myLoop () {           
   setTimeout(function () {   
     i++; 
     $scope.$apply(function() { // Or use $scope.$applyAsync (Preferred)
        $scope.loop.loop = i;
     });
     if (i == $scope.centerWrapMessage.length - 1){
     i = -1;
     }
      if (i < $scope.centerWrapMessage.length) {            
         myLoop();             
      }                        
   }, 2222)
}

Using $timeout

function myLoop () {           
    $timeout(function () {   
      i++; 
      $scope.loop.loop = i;
      if (i == $scope.centerWrapMessage.length - 1){
         i = -1;
      }
      if (i < $scope.centerWrapMessage.length) {            
          myLoop();             
      }                        
  }, 2222)
}

Make sure you've injected $timeout service in your controller.

Sign up to request clarification or add additional context in comments.

4 Comments

Can you explain why this is necessary?
Because angular will not be aware of what happened in timeout. Instead you can use $timeout which will trigger digest for you.
Yes, $timeout will also work or else use $scope.$apply. Both will work.
You could also use $scope.$applyAsync(function(){}) in order to not get an error if the $digest cycle is already running
0

Check out this plunker.

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

app.controller('MainCtrl', ['$scope', '$timeout', function($scope, $timeout) {
  $scope.centerWrapMessage = [
    "Click your category and then click your bread for more information.",
    "If you intend to ship your order, please select a gift box",
    "To add an item to your cart, hit the cart button"
  ];

  $scope.item = 'World';

  var i = 0;
  $scope.item = $scope.centerWrapMessage[i];

  function myLoop () {
    i++;
    $timeout(function() {
      console.log(i, $scope.centerWrapMessage[i]);
      $scope.item = $scope.centerWrapMessage[i];
    }, 0);

    if (i === $scope.centerWrapMessage.length - 1){
      i = 0;
    }
    $timeout(myLoop, 750);
  }

  myLoop();        

}]);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.