How to run lastTask after forEach

I have an array of images that I iterate over and upload each to a remote server. After loading the file, I use the result to get the filename and push to another array.

The problem I'm running into is that not all results are transferred to an array. I am trying to build an array with results for all uploaded images. The following code executes lastTask

until the loop ends forEach

:

    /**
     * Upload picture
     */
    $scope.upload = function () {

      var token = window.localStorage.getItem('yourTokenKey');
      var defer = $q.defer();
      var promises = [];

      var options = {
        fileKey: "image",
        fileName: " test.png",
        chunkedMode: true,
        mimeType: "image/png",
        headers: {'x-auth-token': token}
      };

      function lastTask() {
        alert(promises);
        $scope.images = [];
        $scope.hide();
        $scope.showAlert();
        $scope.putQc();
        alert('finish').then(function () {
          defer.resolve();
        });
      }

      angular.forEach($scope.images, function (image) {
        $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function (result) {
          // Success!
          promises.push(result.response + '.jpg');
          alert(JSON.stringify(result));
          console.log("SUCCESS: " + JSON.stringify(result.response));
          // Error
        }, function (err) {
          alert(JSON.stringify(err));
          console.log("ERROR: " + JSON.stringify(err));
          // constant progress updates
        }, function (progress) {
          $scope.show();
        });
      });

      $q.all(promises).then(lastTask);

      return defer;
};

      

+3


source to share


2 answers


The problem is you are not pushing promises into your promises array. You (end up) pushing normal values โ€‹โ€‹into an array, but not before you run $q.all

on an empty or nearly empty array.

$scope.upload = function() {

    var token = window.localStorage.getItem('yourTokenKey');
    var promises = [];

    var options = {
        fileKey: "image",
        fileName: " test.png",
        chunkedMode: true,
        mimeType: "image/png",
        headers: {
            'x-auth-token': token
        }
    };

    function lastTask(results) {
        alert(results);
        $scope.images = [];
        $scope.hide();
        $scope.showAlert();
        $scope.putQc();
        return results; // keeping the promise chain useful
    }

    angular.forEach($scope.images, function(image) {
        var promiseForUpload = $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function(result) {
            console.log("SUCCESS: " + JSON.stringify(result.response));
            return result.response + '.jpg'; // this will be the promised value
        }, function(err) {
            console.log("ERROR: " + JSON.stringify(err));
            throw err; // re-throwing the error so the q.all promise is rejected
        }, function(progress) {
            $scope.show();
        });
        promises.push(promiseForUpload);
    });

    return $q.all(promises).then(lastTask); // returns a promise for results

};

      

Honestly though I would get rid of the mid-level stuff altogether:



$scope.upload = function() {

    var token = window.localStorage.getItem('yourTokenKey');

    var options = { /* stuff */ };

    function lastTask(results) { // I wouldn't bake this into the $scope.upload, but do it as a result of calling $scope.upload (i.e. with .then).
        alert(results);
        $scope.images = [];
        $scope.hide();
        $scope.showAlert();
        $scope.putQc();
        return results; // keeping the promise chain useful
    }

    var promises = $scope.images.map(function(image){
        return $cordovaFileTransfer.upload("http://server.com/file/upload", image, options);
    });

    return $q.all(promises).then(lastTask); // returns a promise for results

};

      

Finally, if this function is to return a promise, then be sure to add error handling wherever it is used (for example, with a help .catch

at the end of the chain). If this function is supposed to be the end of a promise chain (for example, it is triggered by a button click and does not hear anything), then you need to add a catch to the end $q.all(promises).then(lastTask)

. Avoid silent bugs.

+2


source


If I'm right your array promises

is the problem, instead of pushing promises coming from $cordovaFileTransfer.upload

, you are calling the string result you get.

Second problem, I think you are making an anti-pattern promise , is unnecessary here $q.defer()

.

(thirdly, may be inappropriate, JSON.stringify

really unnecessary, and hopefully alert

determined by you)



I would rewrite it as:

/**
 * Upload picture
 */
$scope.upload = function () {

  var token = window.localStorage.getItem('yourTokenKey');
  var promises = [], results;   //CHANGED

  var options = {
    fileKey: "image",
    fileName: " test.png",
    chunkedMode: true,
    mimeType: "image/png",
    headers: {'x-auth-token': token}
  };

  function lastTask() {
    alert(results);   //CHANGED
    $scope.images = [];
    $scope.hide();
    $scope.showAlert();
    $scope.putQc();
    return alert('finish');   //CHANGED
  }

  promises = $scope.images.map(function (image) {   //CHANGED
    return $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function (result) {   //CHANGED
      // Success!
      results.push(result.response + '.jpg');   //CHANGED
      alert(JSON.stringify(result));
      console.log("SUCCESS: " + JSON.stringify(result.response));
      // Error
    }, function (err) {
      alert(JSON.stringify(err));
      console.log("ERROR: " + JSON.stringify(err));
      throw err;
      // constant progress updates
    }, function (progress) {
      $scope.show();
    });
  });

  return $q.all(promises).then(lastTask);   //CHANGED

};

      

+3


source







All Articles