1

I have an array containing some tests, which I have to run sequentially.
Within an angular forEach loop, I'm iterating over the test array and calling the backend via http get to start the current test.
My problem is now, that the user should have the possibility to stop the test run, so that further tests will not be executed anymore. In the view I have a "Stop test run" button, which sets a $scope.stopTest variable to true. Within my foreach loop I have a condition, which checks the $scope.stopTest variable on each iteration and if it's set to true skips the test run.
But it seems, that inside the loop angular does not recognize the scope variable change from false to true. I had a test output within the loop which shows me that the value was still false.

In my view I have these buttons:

<input type="button" class="btn" ng-click="runTests()" value="Start test run" ng-disabled="disabled == true" />
<input type="button" class="btn" ng-click="stopRunning = true" value="Stop test run" />

In my controller I have this code:

$scope.runTests = function () {

angular.forEach($scope.selected, function (value, key) {

    if (!$scope.stopRunning) { // PROBLEM: angular does not recognize that stopRunning has changed already

        promise = promise.then(function () {

            $scope.count++;
            $scope.status = "Running test " + $scope.count + " of " + $scope.countSelectedTests + ".";

            return $http({
                method: 'GET',
                url: 'api/runtest/' + key
            }).then(function (res) {                            
                   $scope.testresults = res.data;                               
            });
        });   
    }
});

Does anyone know what is the problem here? Is it about child scopes or the digest cycle? I was trying to call $apply() or $digest() after changing the stopRunning variable, but with no effect.

How can I stop the loop by button click event?

1 Answer 1

2

I'm pretty sure the problem* comes from angular's forEach. Have you seen this other question?

*The function itself is not a problem, it's just not supposed to be used in that way.

Okay, scrap that. I think the problem is that your loop happens too quickly. It loops over all your "selected" elements, and launches all the queries before you can even click the stop button. If you want to chain calls, write a recursive function that does the call, and on return, calls itself for the next element. This way, each http call will be started after the previous one is done and you'll have time to interrupt the process.

 function callForEach(selected, i){
     if(i < selected.length){
     var item = selected(i);
     $http({
            method: 'GET',
            url: 'api/runtest/' + key
        }).then(function (res) {                            
               $scope.testresults = res.data;
            if(!$scope.stopRunning){
              callForEach(selected, i+1);
            }                               
        });
     }
 }
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your answer. Yes, I read this question already. But in this case the boolean is not a scope variable and the "loop break" is not triggered from outside by any event.
I think my code runs sequentielly already. That's the reason why I use the promise when instead the .succes and . error callback from the http service, which would run asynchronously indeed. And as soon as a test returns I get a status box in the view informing me about the test results. And this happens slowly one after the other.
You execute the promises sequentially, but.the condition being outside of the promise, it is done in the main thread really quick. Add console.log inside and outside of the promise and you will see how it all plays out.

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.