4

I'm trying to update a progress bar with a sequential http request inside a foreach, this works, but it's not synchronous by on complete, progress bar is being sync'd by the http call, what am I doing wrong?

angular.forEach(queue, function (item) {
    if (item.uid) {
        d.item = item;
        $http({
            url: BASE_URL + 'upp', 
            method: 'post',
            data: d                  
        }).then(function(res){
            x++;
            update_progress((x/queue_count)*100);
        });
    }
});

I would like to call the update_progress function just when the http returns as finished (200 OK), so the progress bar shows the actual progress correctly. Thanks!

Edit:

I tried checking the response status, before calling the *update_progress* function and it still does not work as expected. I wasn't aware that 200 was dispatched before the request is completed :| By logic, the res obj shouldn't be the response of the http request? I mean, if it's 200 and not an error code, that shouldn't mean that the request was completed?

angular.forEach(queue, function (item) {
if (item.uid) {
    d.item = item;
    $http({
        url: BASE_URL + 'upp', 
        method: 'post',
        data: d                  
    }).then(function(res){
        if(res.status == 200) {
          x++;
          update_progress((x/queue_count)*100);
        }
    });
}

Reading more on promises atm to see if I can make it work as stated by @josh-strange

Edit 2:

So promises was the way to do it, all requests are sent sequentially so the progress bar works as expected, here's the code:

var promise = $q.all({}); 
// Had to init $q.all with an empty obj, 'cause null was trowing errors

angular.forEach(queue, function(item){
  if (item.uid) {        
    promise = promise.then(function(){
      d.item = item;
      return $http({
        url: BASE_URL + 'upp', 
        method: 'post',
        data: d 
      }).then(function(res){
        x++;
        update_progress((x/queue_count)*100);
      });
    });
  }
});

promise.then(function(){
  end_js_update();
});

Thanks @josh-strange

5
  • Don't use forEach, manually loop through queue? Not sure that will work either. Async can be such a pain sometimes. Commented Sep 26, 2013 at 20:10
  • You cannot make synchronous calls in AngularJS but you can make sequential http calls (Reg 1, then Reg 2, etc..). Let me try to get a Plunker together for you. Commented Sep 26, 2013 at 20:32
  • Here is an VERY simple example of sequential HTTP requests, I will post an answer in a minute with it cleaned up. Commented Sep 26, 2013 at 20:47
  • @AntonioMax Does my answer below solve you problem? Commented Sep 27, 2013 at 13:10
  • @josh-strange trying to implement the logic on my code. Gonna update & accept if works as expected. Never had to create a promise before, so I'm reading the docs. Commented Sep 27, 2013 at 18:32

3 Answers 3

13

Here is a working Plunker of a working example of sequential http requests. You could obviously package this up very nicely in a service but for your purposes I just put a simple example of it in a controller.

Here is the "meat" of the code:

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

app.controller('myController', function($scope, $http, $q){

  $scope.responses = [];
  $scope.doneLoading = false;
  var urls = [
    'http://httpbin.org/ip',
    'http://httpbin.org/user-agent',
    'http://httpbin.org/headers'
  ];

  var promise = $q.all(null);

  angular.forEach(urls, function(url){
    promise = promise.then(function(){
      return $http({
        method: 'GET', 
        url:url 
      }).then(function(res){
        $scope.responses.push(res.data);
      });
    });
  });

  promise.then(function(){
    //This is run after all of your HTTP requests are done
    $scope.doneLoading = true;
  })

});

EDIT: As Mike P says below: This is an example of chaining promises see $q documentation.

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

2 Comments

Just for completeness, this is an example of chaining promises together (see $q documentation @ docs.angularjs.org/api/ng.$q).
Thanks for adding that Mike, I'll add it to the answer!
0

You could try something like this. Just wait to send the next request until the previous is finished?

var sendRequest = function(index) {
  if (queue[index].uid) {
    d.item = queue[index];
    $http({
      url: BASE_URL + 'upp', 
      method: 'post',
      data: d                  
    }).then(function(res){
      if (index != queue.length - 1) {
        x++;
        update_progress((x / queue_count) * 100);
        sendRequest(++index);
      }
    });
  }
}

1 Comment

thank you, but @josh-strange answer was better because it uses promises, which I believe now is the right way to do it!
0
<button ng-click="vm.startFetchingKeysAndAnswers(vm.selectedTestReader.serial,vm.selectedTestReader.Type)"
    ng-if="vm.isShowStartFetchingbtn==true" id="btnStartFetching"
    type="button" class="btn btn-primary btn-font" style="/*margin-left: 20px;*/">
    Start
</button>
<div class="progress" style="margin-top: 10px;">
    <div id="progressBar" class="progress-bar progress-bar-striped active" role="progressbar"
        aria-valuemin="0" aria-valuemax="100">
        60 %
    </div>
</div>



function startFetchingKeysAndAnswers(testReaderId, type) {
    vm.fetchFailedResultKeysAndAnswers = [];
    vm.apiCallCount = 0;
    vm.isShowStartFetchingbtn == false;
    document.getElementById("btnStartFetching").style.display = "none";
    let errorCount = 0;
    var promise = $q.all({});
    angular.forEach(vm.studentForFetchKeysAndAnswers, function (item) {
        promise = promise.then(function () {
            let userName = type == 2 ? item.Gozine2UserName : KanoonUserName;
            let password = type == 2 ? item.Gozine2Password : KanoonPassword;
            return testReaderService.getKeysAndAnswers(testReaderId, userName, password, item.NationalNo, type)
                .then(function (data) {
                    if (data.data.HasError) {
                        errorCount++;
                        vm.fetchFailedResultKeysAndAnswers.push(item);
                    }
                    vm.apiCallCount++;
                    let percent = vm.apiCallCount / vm.studentForFetchKeysAndAnswers.length * 100;
                    document.getElementById("progressBar").setAttribute("style", "width:" + percent + "%");
                    document.getElementById("progressBar").innerHTML = percent + "%";
                })
        });
    });
    promise.then(function () {

    });
}

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.