AngularJS : 在循环中调用工厂方法

AngularJS : calling a factory method within the loop

我有一个如下所示的工厂方法:

angular.module('GridSamplesApp')
.factory('registerPostFactory', function($resource, $q, WebRequest) {
    var getMessage = function(Upddata, token, dataurl)
    {
            var deferred = $q.defer();
             var settings = {
                data: Upddata,
                headers: {
                  'Content-Type': 'application/JSON',
                  'x-csrf-token' : token
                },
                method: 'POST',
                url: dataurl,
                withCredentials: true
            };
            WebRequest.requestRaw(settings).then(
    function(response) {
      // data from app sec

      var msg = response;

     deferred.resolve(msg);
    },
    function(error) {
      console.log('Error retrieving message', error);
      deferred.reject('Error retrieving message', error);
    });

  return deferred.promise;
    };


  return {
   getMessage: getMessage
  };
   });

我有一个看起来像

的控制器
$scope.getLogs = function()
{

  $.each($scope.modifiedSN, function(i, e) {
      if ($.inArray(e, result) == -1) result.push(e);
  });

  $scope.inputs.push({SN:'', Key:'', status:'', log:''});
  for(var i=0; i<result.length; i++)
  {
    var j = result[i];
    if ($scope.data[j].SerialNumber !== "")
    {


  var Upddata = {};
  Upddata['IConvRuleFlg'] = '';
  Upddata['SrNum'] = $scope.data[j].SerialNumber;
  Upddata['LvEmailId'] = 'abc@xyz.com';
  Upddata['WKey'] = $scope.data[j].WtyKey;

            registerPostFactory.getMessage(Upddata, $scope.token, dataurl).then(
                function(response) {
                  $scope.msg = response.headers["custommessage"];
                  $scope.data[j].AutolinkErrorlog = $scope.msg;
                  $scope.inputs.push({SN: $scope.data[j].SerialNumber, Key: $scope.data[j].WtyKey, status: response.headers["msgtype"], log: $scope.msg});
                },
                function(error) {
                    console.log('Error reading msg: ', error);
                  }
                  );
          }
  }

};

这个问题是它只接受数组中的最后一个元素,因为它是一个异步调用并且循环不会等待响应,我尝试使用 $q.all() 但无法弄清楚如何要实现这个,有人可以帮忙吗?

这里要用到闭包,我修改了你的代码,

(function(data) {
    //console.log(data) //You can notice here, you are getting all individual loop objects
    var Upddata = {};
    Upddata['IConvRuleFlg'] = '';
    Upddata['SrNum'] = data.SerialNumber;
    Upddata['LvEmailId'] = 'abc@xyz.com';
    Upddata['WKey'] = data.WtyKey;

    registerPostFactory.getMessage(Upddata, $scope.token, dataurl).then(
        function(response) {
            $scope.msg = response.headers["custommessage"];
            $scope.data[j].AutolinkErrorlog = $scope.msg;
            $scope.inputs.push({
                SN: data.SerialNumber,
                Key: data.WtyKey,
                status: response.headers["msgtype"],
                log: $scope.msg
            });
        },
        function(error) {
            console.log('Error reading msg: ', error);
        }
    );
})($scope.data[j]);

据我了解,您的工厂工作正常,就像@RaviMone 所说的那样,在 for 循环中使用异步回调代码,您会惊讶于初学者经常掉入该陷阱。另外,我看到一个 $scope.msg,不确定它来自哪里以及它是如何工作的,但是由于您的调用的异步和并行性质,它可能会为各种调用显示错误的值,如果它在每次调用时发生变化,您应该考虑序列化您的调用。

一种更简洁的写法 $scope.getLogs 可能是(我减少了 jQuery 的使用,使用了 ES5 的东西,如果你必须支持遗留系统,你可以使用 this ):

$scope.getLogs = function(){
  var result = [] // again not sure where the result comes from, so initizing it here, else you can append filtered array to the previous set
  $scope.modifiedSN.forEach(function(value) {
      if (result.indexOf(value) < 0) result.push(e);
  });
  $scope.inputs.push({SN:'', Key:'', status:'', log:''});

  var promises = result.map(function(val){
    return $scope.data[val];
  }).filter(function(val){
    return val && val.SerialNumber !== "";  // first check if $scope.data[j] exists
  }).map(function(val){
    return registerPostFactory.getMessage({
        IConvRuleFlg: '',
        LvEmailId: '',
        WKey: val.WtyKey,
        SrNum: val.SerialNumber
    }).then(function(response){
        $scope.msg = response.headers["custommessage"];
        val.AutolinkErrorlog = $scope.msg;
        $scope.inputs.push({SN: val.SerialNumber, Key: val.WtyKey, status: response.headers["msgtype"], log: $scope.msg});
    }).catch(function(e){
        console.log('Error reading msg: ', e);
    });
  });

  $q.all(promises)
    .then(function(resArray){
        console.log('get all logs...');
    }).catch(function(e){
        console.log('some error: ', e);
    });
};

编辑

如果您希望它们按顺序完成:

$scope.getLogs = function(){
  var result = [] // again not sure where the result comes from, so initizing it here, else you can append filtered array to the previous set
    , serialPromise = $q.when(1);   // just initializing a promise.
  $scope.modifiedSN.forEach(function(value) {
      if (result.indexOf(value) < 0) result.push(e);
  });
  $scope.inputs.push({SN:'', Key:'', status:'', log:''});

  result.map(function(val){
    return $scope.data[val];
  }).filter(function(val){
    return val && val.SerialNumber !== "";  // first check if $scope.data[j] exists
  }).forEach(function(val){
    var datum = {
            IConvRuleFlg: '',
            LvEmailId: '',
            WKey: val.WtyKey,
            SrNum: val.SerialNumber
    };
    serialPromise = serialPromise.then(function(){  // adding a new promise to the chain.
        return registerPostFactory.getMessage(datum);
    }).then(function(response){
        $scope.msg = response.headers["custommessage"];
        val.AutolinkErrorlog = $scope.msg;
        $scope.inputs.push({SN: val.SerialNumber, Key: val.WtyKey, status: response.headers["msgtype"], log: $scope.msg});
    }).catch(function(e){
        console.log('Error reading msg: ', e);
    });
  });

  serialPromise.then(function(){
        console.log('got all logs...');
    }).catch(function(e){
        console.log('some error: ', e);
    });
};