1

I have a function in a service that takes a long while to calculate so I would like to show a message on the scope to show it's calculating. I have created a (simplified) jsfiddle here: http://jsfiddle.net/rikboeykens/brwfw3g9/

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

app.service('testService', function(){
    this.longFunction=function(){
        for (var i=0; i<1000000000;i++){


        }
    }
});

function TestCtrl($scope, testService)
{
    $scope.$apply(function(){$scope.waiting="not waiting";});
    $scope.longFunction = function(){
        $scope.waiting="waiting";
        testService.longFunction();
        $scope.waiting="not waiting";
    }
}

The longFunction on the testService takes about two seconds to complete, but $scope.waiting is not updated to "waiting" while this is taking place.

I tried using $scope.$apply but then I just get an error saying $apply is already in progress.

Would it work if I perform the longFunction on the testService asynchronously? I have been looking into using promises but I'm not sure how I would go about implementing them.

2
  • Since your long function is synchronous, there's no way for angular (or any other javascript mechanism) to update the scope. If you want to display messages during a costly calculation, async is indeed the way. Commented May 27, 2015 at 7:06
  • Every answer up to now gets the point. Just as an added value, you may want to take a look at this answer for a way to keep the UI responsive while executing a long-running service. Additionally you may want to look at web workers (probably a much better solution, but I have no experience in it). Commented May 27, 2015 at 8:01

3 Answers 3

2

You can make use of $timeout.

function TestCtrl($scope, testService, $timeout)
{
   $scope.waiting="not waiting";
    $scope.longFunction = function(){
        $scope.waiting="waiting";
        $timeout(function(){
          testService.longFunction();
          $scope.waiting="not waiting";
        })
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

It's working, but you don't see waiting message because longFunction runs synchronously and I suspect that its execution prevents the UI from being painted to show waiting message update. When the longFunction call ends, the UI thread isn't busy and it sets the "not waiting" message preventing you from being able to read the "waiting" text.

This is an expected behavior in Web browsers since everything is executed in the UI thread, and no Web browser can prioritize work if operations are synchronous and the UI gets freezed for a while. Since a long for loop or a long calculation can take a lot of CPU resources, Web browsers need to wait until the operation ends to continue painting the screen.

You can use setTimeout flavor in Angular to simulate an asynchronous operation, and this will give priority to UI and you'll be able to see the message change:

$scope.longFunction = function(){
        $scope.waiting="waiting"; 

        // Actually this is a workaround, because JS doesn't provide
        // an elegant way of enqueueing asynchronous operations in the UI
        // layer. BTW, does Web Workers mean something for you? ;)
        $timeout(function() {
            testService.longFunction();
        }, 0);

        $scope.waiting="not waiting";
}

Comments

1

Definitely you should you $timeout to execute service function. I created and example on Codeopen.io: http://codepen.io/skymk/pen/EjNpKL?editors=101

app.controller('Controller', ['$scope', 'testService', '$timeout',  function($scope, testService, $timeout) {
    $scope.waiting="not waiting";
    $scope.longFunction = function() {
        $scope.waiting="waiting";
        $timeout(function() {
          testService.longFunction();
          $scope.waiting="not waiting";
        }, 0);    
    }
    $scope.longFunction()
}])

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.