如何知道Angular $http正在“请求”

21

当用户点击一个 <button> 时,我会发起一个 $http 请求,并在请求返回 successerror 响应之前禁用/隐藏/显示屏幕上的多个元素。

现在的做法是,我在控制器中定义了一个叫做 $scope.requesting 的变量,并在 HTML 页面中使用它,以判断是否收到了 $http 的响应:

<img src="img/loader.gif" ng-show="requesting" />

基本上当$scope.requesting为真时,显示旋转的ajaxyish加载器。

如果可能的话,我想摆脱$scope.requesting并使用任何$http提供的内容,如果有的话。

登录控制器

function LoginForm($scope, $http)
{
    $scope.requesting = false;

    $scope.login = function()
    {
        $scope.requesting = true;

        $http.post('resources/request.php', data, {timeout:20000})
            .success(function(data, status, headers, config)
            {
                $scope.requesting = false;
            })
            .error(function(data, status, headers, config)
            {
                $scope.requesting = false;
            }
        );
    }
}

+1 我也是这样做的,但在完成时切换请求关闭,而不是在成功或错误时。目前想不到更好的方法。 - Jay
这个链接似乎是你要找的内容。我懒得测试并将其转化为一个正式的答案。也许你可以将最终结果发布为答案。 - Andriy Drozdyuk
@TrevorSenior 好的,知道了,我不是唯一这样做的人。Dmitry的回答似乎很有希望。drozzy,这种行为肯定存在,只是比我目前的解决方案稍微复杂一些。 - Ronnie
@Ronnie 当你询问“$http有什么提供”的时候,你实际上是在谈论$httpProvider。我也认为它很复杂,但恐怕你必须咬紧牙关。 - Andriy Drozdyuk
4个回答

33

您可以利用$http.pendingRequests数组中的配置对象来获取当前正在处理的请求。您可以这样使用它:

$scope.isLoading = function () {
   return $http.pendingRequests.length !== 0;
};

2
那看起来应该可以运行,但是根据 http://docs.angularjs.org/api/ng.$http#pendingRequests 的说法,“pendingRequests”主要是用于调试目的,这有点令人沮丧。我想知道为什么。 - Ronnie
是的,我同意你的观点,这个评论也让我疑惑不安。 顺便一提,我在 Stack Overflow 网站上看到了这个问题:https://dev59.com/sGbWa4cB1Zd3GeqPbNpF ,其中的回答包含了所有需要的链接(特别是这个 https://groups.google.com/forum/#!msg/angular/OroP1DBE6AA/dG4X3M_XvuAJ )。 - Dmitry Evseev
抱歉我是个新手。我从朋友那里听说,当你在应用程序中使用websocket时,查看网络时会显示一个持续/开放的请求(或其他内容)。我想知道这种解决方案是否会将websocket连接检测为挂起的请求。 - Alex Coroza
3
嗨 @boi_echos。Websockets 不使用 HTTP 协议,因此不会显示为挂起的请求。 - Dmitry Evseev
如何检查$resource服务的挂起请求?我知道$resource内部使用$http,但在我的情况下不起作用。我正在尝试在TypeScript中创建指令,以检查挂起的请求。 请查看此问题 http://stackoverflow.com/questions/38226567/create-directive-in-typescript-to-show-loading-progress-in-angular - Microsoft Developer

2

这里的所有答案都没有完全满足我的需求,而我避免使用$http.pendingRequests,所以这是我做的:

我的用例是,如果有任何正在执行服务器操作的请求,我必须在视口顶部显示一个简单的“加载...”消息。

.config中,我注册了一个新的拦截器。在里面,我添加了一个简单的计数器,每个请求增加1,每个响应减少。

$httpProvider.interceptors.push([function () {
    var pendingRequestsCounter = 0;
    return {
        request: function (request) {
            pendingRequestsCounter++;
            if (pendingRequestsCounter > 0) {
                // we have some pending requests, so do something here 
            }
            return request;
        },
        response: function (response) {
            pendingRequestsCounter--;
            if (pendingRequestsCounter === 0) {
                // we have no pending requests, so do something else here 
            }
            return response;
       }
    };
}]);

1
这个 jsbin 项目 将 @DmitryEvseev 的答案推进到了下一步。它提供了更精细的控制,以确定哪些请求可用于触发“加载中...”状态。
那些带有 { showLoader: true } 的请求将被用于显示“加载中...”面板。
HTML
  <div ng-app="app">
    <div ng-controller="spinnerController as vm">
      <div ng-if="vm.isLoading()">Loading ...</div>
    </div>
  </div>

JavaScript
angular
  .module('app', [])
  .config(config)
  .factory('httpLoader', httpLoader)
  .factory('httpLoaderInterceptor', httpLoaderInterceptor)
  .controller('spinnerController', spinnerController);

function config($httpProvider) {
  //adding the default http status code handler
  $httpProvider.interceptors.push('httpLoaderInterceptor');
}

function httpLoader() {
  var pendingReqs = {};
  var factory = {
    addPendingReq: addPendingReq,
    subtractPendingReq: subtractPendingReq,
    getPendingReqs: getPendingReqs
  };
  return factory;

  function addPendingReq(url) {
    console.log('adding url', url);
    pendingReqs[url] = true;
  }

  function subtractPendingReq(url) {

    console.log('removing url', url);
    delete pendingReqs[url];
  }

  function getPendingReqs() {
    return sizeOf(pendingReqs);
  }
}

function httpLoaderInterceptor($q, httpLoader) {

  var factory = {
    request: request,
    response: response,
    responseError: responseError
  };

  return factory;

  function request(config) {
    console.log('request', config.url);
    if (config.showLoader) {
      httpLoader.addPendingReq(config.url);
    }
    return config;
  }

  function response(res) {
    console.log('response', res.config.url);
    if (res.config.showLoader) {
      httpLoader.subtractPendingReq(res.config.url);
    }
  }

  function responseError(res) {
    console.log('responseError', res.config.url);
    if (res.config.showLoader) {
      httpLoader.subtractPendingReq(res.config.url);
    }
    return $q.reject(res);
  }
}

function spinnerController($http, httpLoader) {
  var self = this;
  self.isLoading = function() {
    return httpLoader.getPendingReqs() > 0;
  };

  $http.get('http://stackoverflow.com/posts/34561385',{
    showLoader: true
  });
  $http.get('http://www.amazon.com', {
    showLoader: true
  });
  $http.get('http://www.yahoo.com',{
    showLoader: true
  });
  $http.get('http://www.stackoverflow.com',{
    showLoader: true
  });
}

function sizeOf(obj) {
  var size = 0,
    key;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      size++;
    }
  }
  return size;
}

0
尝试使用这个指令: https://github.com/afeiship/angular-isloading

CSS:

body {
  font-family: 'STHeiti', 'Microsoft YaHei', Helvetica, Arial, sans-serif;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}

.loading-widget {
  width: 100px;
  height: 100px;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  position: absolute;
}

.loading-widget,
.loading-widget[data-visible] {
  display: none;
}

.loading-widget[data-visible=true] {
  display: block;
}

.loading-widget img {
  width: 100%;
  height: 100%;
}

HTML:

<div class="loading-widget"
     isloading
     loading="loading"
     data-visible="{{loading}}"
>
  <img src="svg/default.svg" alt="">
</div>

javascript:

  angular.module('TestApp', ['nx.widget']);

  angular.module('TestApp').
  controller('MainCtrl', function ($http, $q, $rootScope) {
    $rootScope.loading = false;
    var s1 = $http.get('http://www.baidu.com');
    var s2 = $http.get('http://www.sina.com');
    var s3 = $http.get('http://www.163.com');
    var s4 = $http.get('http://www.qq.com');
    var s5 = $http.get('http://www.hao123.com');

    //you need a VPN if you're a Chinese(Thanks to the GFW)
    var s6 = $http.get('https://www.google.com/');


    $q.all([s1, s2, s3, s4, s5, s6]).then(function (responses) {
      console.log(responses);
    })


  });

描述:

  • isloading <!--1.附加指令-->
  • loading="loading" <!--2.将scope.loading写入app.$rootScope-->
  • data-visible="{{loading}}" <!--2.读取loading属性以用于CSS-->

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接