【问题标题】:AngularJS: Show loading spinner on ajax request only after some time has elapsedAngularJS:仅在经过一段时间后才在 ajax 请求上显示加载微调器
【发布时间】:2023-04-09 09:40:01
【问题描述】:

在我的 Angular 应用程序中,我实现了 this directive(下面的代码),它基本上允许我在 Angular 检测到 ajax 请求时显示我选择的元素。

但是,为了稍微提高可用性,我想仅在请求开始后经过一段时间(例如,100 或 200 毫秒)后才显示微调器,以避免在每个请求上出现不必要的瞬间显示.

实现这样的事情的最佳方式是什么?我无法让setTimeoutif 块内正常播放,因为该元素永远不会再次隐藏,即使我不再有待处理的请求。

.directive('loading',   ['$http' ,function ($http)
{
    return {
        restrict: 'A',
        link: function (scope, elm, attrs)
        {
            scope.isLoading = function () {
                return $http.pendingRequests.length > 0;
            };

            scope.$watch(scope.isLoading, function (v)
            {
                if(v){
                    elm.show();
                } else {
                    elm.hide();
                }
            });
        }
    };
}]);

【问题讨论】:

  • 请记住,Angular 有它自己的$timeout 功能,在大多数情况下你应该使用它而不是setTimeout。我的理解是$timeout 等到摘要循环完成后再运行,而setTimeout 不知道摘要循环。
  • 你能解决这个问题吗?我的回答能否为您指明正确的方向?请尽可能分享您的发现
  • @scniro 会的。没有机会实际测试它,因为出现了其他一些事情,但我并没有忘记它。这似乎是正确的方法,实际上可能最终解决了我目前在项目中处理请求的方式的一些其他问题。非常感谢!
  • @Tiago 很酷,很高兴听到。请随时告诉我您的发现
  • 你看看我的工厂怎么样angular-httpshooter,它可以让你更好地控制显示微调器或冻结用户界面,甚至阻止多个调用

标签: javascript angularjs ajax angularjs-directive


【解决方案1】:

听起来您可以利用拦截器并绑定到根变量而不是指令来显示待处理的 ajax 请求的元素(在达到时间阈值之后)。观察以下可能性...

app.factory('HttpInterceptor', ['$rootScope', '$q', '$timeout', function ($rootScope, $q, $timeout) {

    return {
        'request': function (config) {

            $timeout(function() {
                $rootScope.isLoading = true;    // loading after 200ms
            }, 200);

            return config || $q.when(config);   
        },
        'requestError': function (rejection) {
            /*...*/
            return $q.reject(rejection);
        },
        'response': function (response) {       

            $rootScope.isLoading = false;       // done loading

            return response || $q.when(response);
        },
        'responseError': function (rejection) {
            /*...*/
            return $q.reject(rejection);
        }
    };
}]);

// register interceptor
app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.interceptors.push('HttpInterceptor');
    /*...*/
}]);

<!-- plain element with binding -->
<div class="whatever" ng-show="isLoading"></div>

JSFiddle Link - 工作演示

【讨论】:

    【解决方案2】:

    对于单一的、全局可用的加载指示器,http 拦截器可能是更好的策略。但假设您想单独将其附加到单个元素,请尝试以下操作:

    .directive('loading', ['$http', '$timeout', function($http, $timeout) {
        return {
            restrict: 'A',
            link: function(scope, elm, attrs) {
                scope.isLoading = function() {
                    return $http.pendingRequests.length > 0;
                };
    
                if (scope.isLoading) {
                    elm.hide(); // hide the loading indicator to begin with
                    // wait 300ms before setting the watcher:
                    $timeout(function() {
                        var watcher = scope.$watch(scope.isLoading, function(v) {
                            if (v) {
                                elm.show();
                            } else {
                                elm.hide();
                                watcher(); // don't forget to clear $watches when you don't need them anymore!
                            }
                        });
                    }, 300);
                } else {
                    // No pending requests on link; hide the element and stop
                    elm.hide();
    
                }
            }
        };
    }]);
    

    (您可能还应该在指令中包含一个 $destroy 块以调用 watcher(),以防指令超出范围而 http 请求仍处于挂起状态。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-23
      • 1970-01-01
      • 2013-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-21
      相关资源
      最近更新 更多