2013-04-21 83 views
2

我有一些AJAX調用需要爲數組中的每個條目運行,我試圖提供一些關於循環通過數組的循環進度的可視反饋,模型是正確更新,但我沒有看到任何更新的視圖試圖調用循環中的$摘要對DOM沒有影響。AngularJS 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;從循環的結束了。

回答

1

UPDATE

討論後,提交人指出,HTTP請求是同步的。問題仍然是關於「同步」,但有點竅門。看看Angular digest concepts。它基本上運行所有觀察者,表達式(綁定),並且一次又一次地處理所有$evalAsync,直到手錶結果和表達式中沒有更改。在此之後DOM被更新。

所以,問題是所有的同步請求都在摘要週期結束之前被解析,並且DOM呈現將僅在摘要週期結束處理之後發生。

解決你的問題,因爲你的國家,你不能改變API調用異步最簡單的方法,就是確保您的要求是異步,抓住他們的承諾,只有隱藏uploadModal當所有的人都已經完成(這可以通過承諾API實現,參見promises 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服務到控制器關閉。雖然這會解決你的問題,你應該創建一個服務有移動你的加載邏輯,返回一個承諾(更改$範圍引用參數):

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並未掛在上傳過程中,它只是問道並繼續前進。你可以找到關於異步編程herehereherehere的信息。

您必須在上傳回調中將您上傳的計數掛鉤。我不知道你用什麼上傳,但你的$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;  
    }); 
} 

如果您使用$http爲uypload工作,只是返回返回,因爲它已經是一個承諾,改變.then(funciton.success(function。如果沒有,這會變得更復雜一些,你需要閱讀Angular docs on promises

只是一個側面說明,你應該看看Javascript的命名召集。 Javascript通常假設爲cammelCase變量,而不是PascalCase。這裏是David Crackford's convetion

+0

我知道異步JS回調,寧願它,而不是像這個方法那樣鎖定UI,但不幸的是,在這種情況下,框架包裝它的Ajax調用作爲同步操作,可怕的是我知道,但很少有機會改變它。 – Baxter 2013-04-21 14:13:00

+0

你會發布你的uploadEntry函數嗎? – 2013-04-21 14:19:13

+0

好的,這個例子現在被修改了。 – Baxter 2013-04-21 14:31:13