2014-09-28 50 views
1

我想提出一个页面AngularJS以及其中角JS控制器通过调用通过ajax一些servlet方法异步初始化其模型的一些jQuery插件。我想在第一次ajax调用开始时显示加载gif,并在最后一次ajax调用结束时将其隐藏。显示等待中的Gif为多个异步AJAX调用

因为我不知道这将是最后一个Ajax调用来完成,我不知道在哪里放置说明隐藏加载GIF。我如何实现这种行为?

的我想要什么的代码示例:

myApp.controller("adminCtrl", function($scope, $http) { 
    $scope.initData1 = function() { 
     /* is this the first call? then show the gif */ 
     $http(...).success(function() { /* is this the last response received? then hide the gif */}); 
    } 

    $scope.initData2 = function() { 
     /* is this the first call? then show the gif */ 
     $http(...).success(function() { /* is this the last response received? then hide the gif */}); 
    } 

    $scope.initData3 = function() { 
     /* is this the first call? then show the gif */ 
     $http(...).success(function() { /* is this the last response received? then hide the gif */}); 
    } 

    initData1(); 
    initData2(); 
    initData3(); 
} 

我希望你明白我的问题,并知道任何方式来实现这一目标。

+0

我接受@Valentin Waeselynck的答案,因为它是可重复使用的多个控制器(这是我的情况),也因为我不能肯定,如果使用的承诺Chandermani的答案会像IE8浏览器+工作(这也是我的情况)。尽管如此,我认为Chandermani对承诺的回答是现代浏览器的最佳方法。装载栏也很酷。 – 2014-09-30 16:19:07

回答

1

这个怎么样:声明一个服务,你可以注册待处理的任务,然后声明它们完成。

myApp.factory('pendingService', [function() { 
    var pendingTasksCount = 0; 

    return { 
    anyPending: function() { 
     return pendingTasksCount > 0; 
    }, 
    registerNewTask: function() { 
     pendingTasksCount += 1; 
     return function declareTaskDone() { 
     pendingTasksCount -= 1; 
     } 
    } 
    }; 
}]); 

然后在你的控制器:

myApp.controller("adminCtrl", function($scope, $http, pendingService) { 

    // expose "any pending task" property in scope 
    $scope.showGif = pendingService.anyPending; 

    $scope.initData1 = function() { 
    var declareDone = pendingService.registerNewTask(); 
    $http(...).success(function() { 
     // do stuff 
     // ... 
     declareDone(); 
    }); 
    }; 

    $scope.initData2 = function() { 
    var declareDone = pendingService.registerNewTask(); 
    $http(...).success(function() { 
     // do stuff 
     // ... 
     declareDone(); 
    }); 
    }; 

    $scope.initData3 = function() { 
    var declareDone = pendingService.registerNewTask(); 
    $http(...).success(function() { 
     // do stuff 
     // ... 
     declareDone(); 
    }); 
    }; 

    initData1(); 
    initData2(); 
    initData3(); 
}); 

而在HTML:

<img src="mygifurl" alt="loading" ng-show="showGif()"/> 

如果您需要此行为是局部的,不是全球性的,你可以使用同一个工厂创建一个本地对象。

+0

我喜欢这个答案,因为它是独立于控制器的,因此可以在其他控制器中重用,这是我的情况。谢谢 – 2014-09-29 16:46:22

+0

我需要使用$ scope。$ apply()对declareDone()或registerNewTask()更新我的视图吗? – 2014-09-29 17:00:31

+0

在我的项目中处于这种情况下,我会说你通常不需要,因为触发'registerNewTask()'或'declareDone()'的事件已经是角循环的一部分(例如:点击按钮,然后是HTTP响应)。 – 2014-09-29 18:29:27

2

看为http://chieffancypants.github.io/angular-loading-bar/进度栏,使得可以显示进度永远的HTTP请求时。它基本上是一个http拦截器,用于跟踪http请求的数量并相应地显示\隐藏进度条。

如果你想解决这个特定的情况,你可以使用$ q.all来实现这个行为。首先所有的init *函数返回的HTTP承诺

$scope.initData1 = function() { 
     /* is this the first call? then show the gif */ 
     var promise = $http(...); 
     promise.success(function(data) { // handle data}); 
     return promise; 
    } 

现在调用代码只是做

//show animation 
$q.all([$sope.initData1(),$sope.initData2(),$sope.initData3()]).then(function(responseArray) { 
    //hide animation 
}) 
+0

我真的很喜欢那个进度条,但我不知道它会如何反应多个并发的ajax帖子。它会等待最后一个完成,还是会重新启动每一个新的ajax调用? (无论如何,我会试试看) – 2014-09-29 16:49:32

+0

另一个问题,既然$ q是ES6的实现,是不是只支持ES6的浏览器?至少我可以在IE8上运行它吗?我是否需要额外的插件(Ej。jQuery)来模拟所需的ES6功能? – 2014-09-29 16:56:15

0

可以使用$.active检查活动的Ajax请求有多少都在进步。

myApp.controller("adminCtrl", function($scope, $http) { 
    $scope.initData1 = function() { 
     if($.active==0){ 
      //this is the last active ajax request 
     } 
     /* is this the first call? then show the gif */ 
     $http(...).success(function() { /* is this the last response received? then hide the gif */}); 
    } 

    $scope.initData2 = function() { 
     if($.active==0){ 
      //this is the last active ajax request 
     } 
     /* is this the first call? then show the gif */ 
     $http(...).success(function() { /* is this the last response received? then hide the gif */}); 
    } 

    $scope.initData3 = function() { 
     if($.active==0){ 
      //this is the last active ajax request 
     } 
     /* is this the first call? then show the gif */ 
     $http(...).success(function() { /* is this the last response received? then hide the gif */}); 
    } 

    initData1(); 
    initData2(); 
    initData3(); 
} 
+0

如果这个工作,惯用的角度方式,而不是暴露范围恕我直言的$ .active属性。 – 2014-09-28 05:48:25

+0

我更喜欢角​​相关的解决方案,而不是jQuery相关的解决方案,因为我只使用jQuery进行一些插件并在angularjs中管理所有控制器逻辑。另外,jQuery如何知道angularjs ajax帖子? – 2014-09-29 16:43:53

0

我会为此使用ngClass和一个计数器变量,例如, 。

<html ng-app="testApp"> 
    <head> 
     <style class="text/css"> 
      .showing { 
       /* instead of this, you can add your gif here */ 
       background: #f0f; 
      } 
     </style> 
    </head> 
    <body ng-controller="TestController"> 
     <div class="test" ng-class="{'showing': count > 0 && count < 3}"> 
      Count: {{count}} 
     </div> 
     <script type="text/javascript" src="angular.min.js"></script> 
     <script type="text/javascript"> 
      (function() { 
       var testApp = angular.module("testApp", []); 
       testApp.controller("TestController", function($scope) { 
        $scope.count = 0; 

        var timeout = function(t) { 
         // this represents your ajax callbacks 
         setTimeout(function() { 
          $scope.$apply(function() { 
           $scope.count = $scope.count + 1; 
          }); 
         }, t * 1000); 
        }; 

        timeout(1); 
        timeout(2); 
        timeout(3); 
       }); 
      })(); 
     </script> 
    </body> 
</html> 

您需要修改$范围内的范围$应用功能方面(在这个特殊的例子),或您的视图不会更新(关于为什么出现这种情况的更多信息,请参见:http://www.jeffryhouser.com/index.cfm/2014/6/2/How-do-I-run-code-when-a-variable-changes-with-AngularJS)。如果你使用承诺,你可以避免这个问题,但我相信使用ngClass是修改视图的角度。

+0

在这种情况下,我假设我应该保留一个'count' $ scope变量并在每个ajax post/response上递增/递减它。它是否正确? – 2014-09-29 16:40:59

+0

是的,你应该在每次ajax调用返回的时候增加一个'count'变量(正如你在示例中看到的那样)。你可以将这种方法与Chandermani建议的方法混合,一旦所有的承诺完成,你就可以拥有一个布尔标志,ngClass可以根据需要使用它来添加或删除类。 – emerino 2014-09-29 16:46:50