2

我有许多 AJAX 调用需要为数组中的每个条目运行,我试图提供一些关于通过数组的循环进度的视觉反馈,模型正在正确更新但我没有看到试图在循环中调用 $digest 的视图中更新的任何内容都不会影响 DOM。

我尝试将 $apply 添加到内部循环中的函数,但我仍然没有看到任何变化。

$scope.UploadEntry = function(item){
var oDBGet = new htmldb_Get(null, 
                            $v('pFlowId'), 
                            "APPLICATION_PROCESS=UploadTargetDates", 
                            $v('pFlowStepId'));

oDBGet.add('EX_TRD',$scope.Ext.TRDDate.val);
oDBGet.add('EX_MAX_TRD',$scope.Ext.MaxTRDDate.val);
oDBGet.add('EX_READ',Ext.ReadDownloadCheck);
oDBGet.get();
};

$scope.ShowUploadModal = true;
$scope.UploadDone = 0;
for(i in submissionList)
{
        $scope.UploadEntry(submissionList[i]);
        $scope.UploadDone += 1;
}
$scope.ShowUploadModal = false;

但观点:

<div class="UploadModal" ng-show="ShowUploadModal">
Uploading entries: {{UploadDone}} complete
</div>

从未见过条目已上传,但如果我 $scope.ShowUploadModal = false;从循环末尾取出,它会显示在循环末尾。

4

1 回答 1

1

更新

经过讨论,作者声明http请求是同步的。问题仍然是关于“同步性”,但有点棘手。看看Angular 摘要概念。它基本上一遍又一遍地运行所有的观察者、表达式(绑定)和进程$evalAsync,直到观察者的结果和表达式不再发生变化。就在这之后,DOM 被更新。

因此,问题在于您的所有同步请求都在摘要周期结束之前得到解决,并且 DOM 渲染只会在摘要周期完成处理后发生。

解决您的问题的最简单方法,正如您所说,您不能更改 API 来调用异步,是确保您的请求是异步的,获取他们的承诺,并且仅在所有请求都完成后隐藏 uploadModal(这可以通过承诺来实现API,阅读承诺 API$timeout)。像这样:

var loadingPromises = [];

$scope.ShowUploadModal = true;
$scope.UploadDone = 0;

for(i in submissionList) {
  loadingPromises.push($timeout((function(index) {
    return function() {
      $scope.UploadEntry(submissionList[index]);
      $scope.UploadDone += 1;
    };
  })(i), 0));
}

$q.all(loadingPromises).then(function() {
  $scope.ShowUPloadMOdel = false;
});

请注意我创建的闭包以确保将正确的索引传递给请求,并且您需要向$q控制器注入服务。尽管这将解决您的问题,但您应该创建一个服务并将您的加载逻辑移到那里,返回一个承诺(将您的 $scope 引用更改为参数):

app.service('yourLoaderService', function($timeout) {
  this.load = function(url) {
    return $timeout(function() {
      var oDBGet = new htmldb_Get(null, 
                        $v('pFlowId'), 
                        "APPLICATION_PROCESS=UploadTargetDates", 
                        $v('pFlowStepId'));

      oDBGet.add('EX_TRD',$scope.Ext.TRDDate.val);
      oDBGet.add('EX_MAX_TRD',$scope.Ext.MaxTRDDate.val);
      oDBGet.add('EX_READ',Ext.ReadDownloadCheck);
      oDBGet.get();
    }, 0);
  };
});

和你的控制器:

var loadingPromises = [];

$scope.ShowUploadModal = true;
$scope.UploadDone = 0;

for(i in submissionList) {
  var promise = yourLoaderService.load(submissionList[i]).then(function() {
    $scope.UploadDone++;
  });

  loadingPromises.push(promise);
}

$q.all(loadingPromises).then(function() {
  $scope.ShowUPloadMOdel = false;
});

第一个答案

这是一个概念错误。你好像来自同步服务器端背景,可能是Python,我不知道。如果这是您的真实代码,那么问题在于您的代码是完全同步的。您正在显示上传模型,循环所有条目并隐藏模型,并且整个代码在 DOM 被渲染一次之前发生在几毫秒(或更短)内。

发生这种情况是因为当您请求上传时,Javascript 不会在上传过程中挂起,它只是请求并继续。您可以在此处此处此处此处找到有关异步编程的信息。

您必须在上传回调中连接您上传的计数。我不知道你用什么来上传,但你$scope.uploadEntry应该返回一个promise,然后你等待它完成并更新计数。

$scope.ShowUploadModal = true;
$scope.UploadDone = 0;
for(i in submissionList)
{
  $scope.UploadEntry(submissionList[i]).then(function() {
    $scope.UploadDone += 1;
    scope.ShowUploadModal = $scope.UploadDone !== submissionList.length;      
  });
}

如果您正在使用$httpuypload 作业,只需将其返回即可,因为它已经是一个承诺并且.then(funciton.success(function. 如果没有,这会有点复杂,你需要阅读有关 promises 的 Angular 文档

顺便说一句,您应该看看 Javascript 命名约定。Javascript 通常假设cammelCase变量,而不是PascalCase. 这是大卫克拉克福德的对流

于 2013-04-21T13:52:16.153 回答