如何防止 angular 在所有数据都出现之前呈现页面?

How to prevent angular to render page until all data will be present?

我有以下问题: 我试图从 MongoDB 的两个集合中获取 "merge" 数据。 一切看起来都很好,直到我尝试显示恰好在第一个查询之后出现的第二个查询的一些数据:

$scope.getData = function() {
 var pipeline, fromDateRangeStatement, toDateRangeStatement, service, joblist;
 service = ($scope.service && $scope.service.value) ? $scope.service.value : {
     $exists: true
 };
 pipeline = $scope.utils.getSessionUsersPipeline($scope.fromDate, $scope.toDate,
     $scope.checkedResults, $scope.checkedStatuses, service, $stateParams, $scope.usersLimit);
 toApi.post("/users/aggregate", {
     pipeline: pipeline
 }).success(function(data) {
     $scope.users = data.data.result;
     for (var i = 0; i < $scope.users.length; i++) {
         var path = "/jobs/" + scope.users[i].id + "/sessions";
         var user = $scope.users[i]
         toApi.get(path).success(function(data) {
             user.error = data.data.records[0].exception // this is not shows up in HTML!
             console.log(data.data.records[0].exception); // but it can be logged!
         })
     }
 })

};

所以,问题是:$scope.users 在我的页面上呈现,而它们的属性 error 没有。看起来数据在我为 for 循环中的每个用户更改属性之前就已呈现。 如何处理? 谢谢

var user = $scope.users[i]只赋$scope.users[i]的值。所以稍后当您执行 user.error=... 时,它不会更改 $scope。试试这个:

for (var i = 0; i < $scope.jobs.length; i++) {
  var path = "/jobs/" + scope.users[i].id + "/sessions";
  toApi.get(path).success(function(data){
    $scope.users[i].error = data.data.records[0].exception // this is not shows up in HTML!
    console.log(data.data.records[0].exception); // but it can be logged!
  })
}

下面是两种不同的解决方案


您的每个 GET 请求都是异步的,因此您需要等待所有请求都得到解决。您可以将每个请求包装在自己的 Promise 中,并像这样收集所有 Promise

var promises = [];
for (var i = 0; i < $scope.users.length; i++) {
  promises[i] = new Promise(function (resolve, reject) {
    var path = "/jobs/" + scope.users[i].id + "/sessions";
    var user = $scope.users[i]
    toApi.get(path).success(function(data){
      user.error = data.data.records[0].exception;
      console.log(data.data.records[0].exception);
      resolve(user);
  })
}

然后使用 Promise.all() 将所有 promise 组合为一个 Promise 并等待它 resolve。

Promise.all(promises).then(function(users) { 
  $scope.users = users;
});

简单示例:http://codepen.io/C14L/pen/QNmQoN


不过,一个更简单更好的解决方案是一个接一个地显示用户,因为他们的 API 呼叫 return

for (var i = 0; i < $scope.users.length; i++) {
  var path = "/jobs/" + $scope.users[i].id + "/sessions";
  toApi.get(path).success(function (data) {
      $scope.users[i].error = data.data.records[0].exception;
      $scope.users[i].done = true;
      console.log(data.data.records[0].exception);
  });
}

只需在您的模板中添加对 $scope.users[i].done = true 的检查,然后只显示带有 ng-show="user.done".

的数据集

关于处理此问题的 2 个要素:

如果您使用 {{value}} 将其替换为

<span ng-bind="value"></span>

所以你不会看到括号。

现在您想在更改任何内容之前等待所有请求,以免显示部分数据。这也很简单:

var promiseArray = []; 
for (var i = 0; i < $scope.users.length; i++) {
     var path = "/jobs/" + scope.users[i].id + "/sessions";
     var user = $scope.users[i]
     promiseArray.push(toApi.get(path)).success(function(data){
         var result = {i:i, data:data};
         return result
     });
 }
 $q.all(promiseArray).then(function success(result){
     for(var i=0; i < promiseArray.length;i++){
        $scope.users[result.i].error = result.data.data.records[0].exception;
     }
 });

基本上,在更改任何数据之前,我正在等待所有请求被重新处理,因此这将 运行 在同一个 angular 循环中。所以 DOM 只会刷新一次,用户不会看到任何部分结果。