如何在所有数据出现之前阻止角度渲染页面?

时间:2016-04-14 08:49:35

标签: javascript angularjs angular-resource

我有以下问题: 我试图从MongoDB的两个集合中“合并”数据。 一切都看起来不错,直到我尝试显示第二个查询之后的第一个数据:

$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循环中的每个用户更改属性之前,看起来数据已呈现。 如何处理? 感谢

3 个答案:

答案 0 :(得分:3)

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

您的每个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.all(promises).then(function(users) { 
  $scope.users = users;
});

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

尽管如此,更简单,更好的解决方案是逐个显示用户,因为他们的API调用返回

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"的数据集。

答案 1 :(得分:1)

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!
  })
}

答案 2 :(得分:1)

关于处理此问题的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;
     }
 });

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