Hiển thị GIF spinner trong yêu cầu $ http trong AngularJS?


234

Tôi đang sử dụng $httpdịch vụ của AngularJS để thực hiện yêu cầu Ajax.

Làm thế nào một GIF spinner (hoặc một loại chỉ báo bận khác) có thể được hiển thị trong khi yêu cầu Ajax đang thực thi?

Tôi không thấy bất cứ điều gì giống như ajaxstarteventtrong tài liệu AngularJS.


2
Nếu bạn muốn một công cụ quay vòng đơn giản dựa trên Bộ chặn HTTP, tôi có một mô-đun góc cho điều đó. Nó sử dụng spinner Nhận dạng Sham phổ biến. Hãy xem: github.com/harinair/angular-sham-spinner
Hari Gangadharan

1
Tôi đã viết một plugin angular-httpshooter , nó phát hành một sự kiện với dữ liệu cấu hình ngay trước khi thực hiện cuộc gọi và phát hành một cái khác ngay sau khi nhận được resposne, bạn có thể viết trình tải toàn cầu bắt những sự kiện đó
Siddharth

Câu trả lời:


88

Dưới đây là câu thần chú AngularJS hiện tại :

angular.module('SharedServices', [])
    .config(function ($httpProvider) {
        $httpProvider.responseInterceptors.push('myHttpInterceptor');
        var spinnerFunction = function (data, headersGetter) {
            // todo start the spinner here
            //alert('start spinner');
            $('#mydiv').show();
            return data;
        };
        $httpProvider.defaults.transformRequest.push(spinnerFunction);
    })
// register the interceptor as a service, intercepts ALL angular ajax http calls
    .factory('myHttpInterceptor', function ($q, $window) {
        return function (promise) {
            return promise.then(function (response) {
                // do something on success
                // todo hide the spinner
                //alert('stop spinner');
                $('#mydiv').hide();
                return response;

            }, function (response) {
                // do something on error
                // todo hide the spinner
                //alert('stop spinner');
                $('#mydiv').hide();
                return $q.reject(response);
            });
        };
    });

//regular angular initialization continued below....
angular.module('myApp', [ 'myApp.directives', 'SharedServices']).
//.......

Đây là phần còn lại của nó (HTML / CSS) .... bằng cách sử dụng

$('#mydiv').show(); 
$('#mydiv').hide(); 

để chuyển đổi nó. LƯU Ý: ở trên được sử dụng trong mô-đun góc ở đầu bài

#mydiv {  
    position:absolute;
    top:0;
    left:0;
    width:100%;
    height:100%;
    z-index:1000;
    background-color:grey;
    opacity: .8;
 }

.ajax-loader {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -32px; /* -1 * image width / 2 */
    margin-top: -32px;  /* -1 * image height / 2 */
    display: block;     
}

<div id="mydiv">
    <img src="lib/jQuery/images/ajax-loader.gif" class="ajax-loader"/>
</div>

19
Lưu ý rằng bạn có thể sử dụng angular.element('#mydiv').show()thay vì$('#mydiv').show()
JMaylin

8
điều này không hoạt động nếu trang của bạn thực hiện nhiều yêu cầu ajax. Nó sẽ ẩn gif tải sau khi yêu cầu đầu tiên kết thúc.
Meeker

38
Theo các thực tiễn tốt nhất của AngularJS (mà giải pháp được chấp nhận đang vi phạm), bạn không nên sửa đổi DOM bên ngoài chỉ thị. Xem xét việc gọi chương trình / ẩn trên các phần tử từ trong một lệnh.
Mariusz

7
Tôi không chắc mình biết đủ để bình luận ... Nhưng liệu có đúng không khi thực hiện việc này là sử dụng lệnh ng-classthay vì sử dụng JQuery để hiển thị và ẩn các phần tử?
James Heald

2
@JamesHeald là chính xác .. bạn không bao giờ thực sự cần phải sử dụng jQuery cho bất kỳ thao tác dom nào trong Angular. Nhìn vào: ng-class, ng-if, ng-hide, ng-show, v.v .. có một chỉ thị cho hầu hết mọi thứ bạn cần.
jKlaus

471

Điều này thực sự phụ thuộc vào trường hợp sử dụng cụ thể của bạn, nhưng một cách đơn giản sẽ theo một mô hình như thế này:

.controller('MainCtrl', function ( $scope, myService ) {
  $scope.loading = true;
  myService.get().then( function ( response ) {
    $scope.items = response.data;
  }, function ( response ) {
    // TODO: handle the error somehow
  }).finally(function() {
    // called no matter success or failure
    $scope.loading = false;
  });
});

Và sau đó phản ứng với nó trong mẫu của bạn:

<div class="spinner" ng-show="loading"></div>
<div ng-repeat="item in items>{{item.name}}</div>

223
Nếu bạn có nhiều yêu cầu ajax cùng một lúc, bạn có thể khai báo loadingdưới dạng một số nguyên $scope.loading = 0;, khi một yêu cầu bắt đầu bạn thực hiện $scope.loading++;và khi nào nó kết thúc thì bạn thực hiện $scope.loading--;. Và không có gì để thay đổi trong mẫu. Vì vậy, spinner được hiển thị khi có ít nhất một yêu cầu đang diễn ra và được ẩn trong phần còn lại của thời gian
JMaylin

16
Có lẽ bạn cũng nên đặt tải thành false trong chức năng dự phòng lỗi.
sebnukem

3
@sebnukem Đúng rồi bạn. Đây là một ví dụ khá cao cấp, nhưng tôi đã tiếp tục và thêm nó vào cho rõ ràng. Cảm ơn vì bạn đã phản hồi!
Josh David Miller

1
@JMaylin - sau đó bạn có thể sử dụng $ watch trên $ scope.loading làm những việc khác
Jason

5
Một cách thậm chí còn sạch hơn, thay vì đặt $scope.loading = falsecả thành công và gọi lại thất bại, là đưa nó vào .finally(). Nó sẽ giống như:mySvc.get().then(success, fail).finally(function() { $scope.loading = false; });
Tom

44

Đây là một phiên bản sử dụng một directiveng-hide.

Điều này sẽ hiển thị trình tải trong tất cả các cuộc gọi thông qua $httpdịch vụ của angular .

Trong mẫu:

<div class="loader" data-loading></div>

chỉ thị:

angular.module('app')
  .directive('loading', ['$http', function ($http) {
    return {
      restrict: 'A',
      link: function (scope, element, attrs) {
        scope.isLoading = function () {
          return $http.pendingRequests.length > 0;
        };
        scope.$watch(scope.isLoading, function (value) {
          if (value) {
            element.removeClass('ng-hide');
          } else {
            element.addClass('ng-hide');
          }
        });
      }
    };
}]);

bằng cách sử dụng ng-hidelớp trên phần tử, bạn có thể tránh được jquery.


Tùy chỉnh: thêm một interceptor

Nếu bạn tạo một trình chặn chặn tải, bạn có thể hiển thị / ẩn trình tải dựa trên một điều kiện.

chỉ thị:

var loadingDirective = function ($rootScope) {
  return function ($scope, element, attrs) {
      $scope.$on("loader_show", function () {
          return element.removeClass('ng-hide');
      });
      return $scope.$on("loader_hide", function () {
          return element.addClass('ng-hide');
      });
  };
};

đánh chặn:

  • ví dụ: không hiển thị spinnerkhiresponse.background === true;
  • Chặn requestvà / hoặc responseđể thiết lập $rootScope.$broadcast("loader_show");hoặc$rootScope.$broadcast("loader_hide");

thêm thông tin về việc viết một máy bay đánh chặn


@punkrockpolly Trong kịch bản cụ thể của tôi, tôi có hai thành phần không chính thức gọi một dịch vụ. Nhưng điều này chỉ hoạt động đối với một trong số họ, tôi có nên truyền tham số hoặc thứ gì đó để làm cho nó có thể tái sử dụng không?
RicardoGonzales

@razorblade nó sẽ quay bất cứ khi nào bạn thực hiện cuộc gọi thông qua $httpbất kỳ dịch vụ nào.
punkrockpolly

31

Nếu bạn đang sử dụng ngResource, thuộc tính $ được giải quyết của một đối tượng rất hữu ích cho các trình tải:

Đối với một tài nguyên như sau:

var User = $resource('/user/:id', {id:'@id'});
var user = User.get({id: 1})

Bạn có thể liên kết trình tải với thuộc tính $ được giải quyết của đối tượng tài nguyên:

<div ng-hide="user.$resolved">Loading ...</div>


13

Chỉ cần phát hiện ra lệnh angular-busyhiển thị một trình tải nhỏ tùy thuộc vào một số cuộc gọi không đồng bộ.

Ví dụ: nếu bạn phải thực hiện GET, hãy tham khảo lời hứa trong $scope,

$scope.req = $http.get('http://google.fr');

và gọi nó như vậy:

<div cg-busy="req"></div>

Đây là GitHub.

Bạn cũng có thể cài đặt nó bằng cách sử dụng bower(đừng quên cập nhật các phụ thuộc dự án của bạn):

bower install angular-busy --save

Tôi không thể tìm thấy cách "vô hiệu hóa một số yếu tố" trong tài liệu. Bạn có thể giải thích như thế nào? Ví dụ, tôi muốn tắt một nút trong khi trình quay được hiển thị.
c4k

angular-busy chỉ đặt trên phần tử của bạn một mặt nạ, tôi không nghĩ bạn có thể vô hiệu hóa một nút như bạn muốn làm, nhưng bạn có thể đặt phông nền trên đó với một mẫu trống để tạo ấn tượng này. Tôi không phải là người bản ngữ, xin lỗi vì sự nhầm lẫn :)
Balthazar

Ok, tôi đã chỉnh sửa câu trả lời của bạn để ngăn người khác có cùng sự nhầm lẫn. Một người Pháp nói tiếng Anh với một người Pháp khác luôn khó hiểu :)
c4k

5

Nếu bạn đang gói các cuộc gọi api của mình trong một dịch vụ / nhà máy, thì bạn có thể theo dõi bộ đếm tải ở đó (theo câu trả lời và đề xuất đồng thời tuyệt vời của @JMaylin) và tham chiếu bộ đếm tải thông qua một lệnh. Hoặc bất kỳ sự kết hợp của chúng.

API VIẾT

yourModule
    .factory('yourApi', ['$http', function ($http) {
        var api = {}

        //#region ------------ spinner -------------

        // ajax loading counter
        api._loading = 0;

        /**
         * Toggle check
         */
        api.isOn = function () { return api._loading > 0; }

        /**
         * Based on a configuration setting to ignore the loading spinner, update the loading counter
         * (for multiple ajax calls at one time)
         */
        api.spinner = function(delta, config) {
            // if we haven't been told to ignore the spinner, change the loading counter
            // so we can show/hide the spinner

            if (NG.isUndefined(config.spin) || config.spin) api._loading += delta;

            // don't let runaway triggers break stuff...
            if (api._loading < 0) api._loading = 0;

            console.log('spinner:', api._loading, delta);
        }
        /**
         * Track an ajax load begin, if not specifically disallowed by request configuration
         */
        api.loadBegin = function(config) {
            api.spinner(1, config);
        }
        /**
         * Track an ajax load end, if not specifically disallowed by request configuration
         */
        api.loadEnd = function (config) {
            api.spinner(-1, config);
        }

        //#endregion ------------ spinner -------------

        var baseConfig = {
            method: 'post'
            // don't need to declare `spin` here
        }

        /**
         * $http wrapper to standardize all api calls
         * @param args stuff sent to request
         * @param config $http configuration, such as url, methods, etc
         */
        var callWrapper = function(args, config) {
            var p = angular.extend(baseConfig, config); // override defaults

            // fix for 'get' vs 'post' param attachment
            if (!angular.isUndefined(args)) p[p.method == 'get' ? 'params' : 'data'] = args;

            // trigger the spinner
            api.loadBegin(p);

            // make the call, and turn of the spinner on completion
            // note: may want to use `then`/`catch` instead since `finally` has delayed completion if down-chain returns more promises
            return $http(p)['finally'](function(response) {
                api.loadEnd(response.config);
                return response;
            });
        }

        api.DoSomething = function(args) {
            // yes spinner
            return callWrapper(args, { cache: true });
        }
        api.DoSomethingInBackground = function(args) {
            // no spinner
            return callWrapper(args, { cache: true, spin: false });
        }

        // expose
        return api;
    });

TRỰC TIẾP SPINNER

(function (NG) {
    var loaderTemplate = '<div class="ui active dimmer" data-ng-show="hasSpinner()"><div class="ui large loader"></div></div>';

    /**
     * Show/Hide spinner with ajax
     */
    function spinnerDirective($compile, api) {
        return {
            restrict: 'EA',
            link: function (scope, element) {
                // listen for api trigger
                scope.hasSpinner = api.isOn;

                // attach spinner html
                var spin = NG.element(loaderTemplate);
                $compile(spin)(scope); // bind+parse
                element.append(spin);
            }
        }
    }

    NG.module('yourModule')
        .directive('yourApiSpinner', ['$compile', 'yourApi', spinnerDirective]);
})(angular);

SỬ DỤNG

<div ng-controller="myCtrl" your-api-spinner> ... </div>

5

Đối với tải trang và phương thức, cách dễ nhất là sử dụng lệnh ng-showvà sử dụng một trong các biến dữ liệu phạm vi. Cái gì đó như:

ng-show="angular.isUndefined(scope.data.someObject)".

Ở đây, trong khi someObjectkhông được xác định, spinner sẽ hiển thị. Khi dịch vụ trả về với dữ liệu và someObjectđược điền, spinner sẽ trở về trạng thái ẩn.


3

Đây là cách dễ nhất để thêm một spinner tôi đoán: -

Bạn có thể sử dụng ng-show với thẻ div của bất kỳ một trong số những người quay đẹp này http://tobiasahlin.com/spinkit/ {{Đây không phải là trang của tôi}}

và sau đó bạn có thể sử dụng loại logic này

//ajax start
    $scope.finderloader=true;
    
          $http({
    method :"POST",
    url : "your URL",
  data: { //your data
     
     }
  }).then(function mySucces(response) {
    $scope.finderloader=false;
      $scope.search=false;          
    $scope.myData =response.data.records;
  });
     
    //ajax end 
    
<div ng-show="finderloader" class=spinner></div>
//add this in your HTML at right place


3
Based on Josh David Miller response:

  <body>
  <header>
  </header>
<div class="spinner" ng-show="loading">
  <div class="loader" ></div>
</div>

<div ng-view=""></div>

<footer>
</footer>

</body>

Thêm css này:

    .loader {
  border: 16px solid #f3f3f3;
  border-radius: 50%;
  border-top: 16px solid #3498db;
  border-bottom : 16px solid black;
  width: 80px;
  height: 80px;
  -webkit-animation: spin 2s linear infinite;
  animation: spin 2s linear infinite;
  position: absolute;
  top: 45%;
  left: 45%;
}

@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}


.spinner{
  width: 100%;
height: 100%;
z-index: 10000;
position: absolute;
top: 0;
left: 0;
margin: 0 auto;
text-align: center;
vertical-align: middle;
background: white;
opacity: 0.6;
}

Và chỉ trong góc thêm của bạn:

$ rootScope.loading = false; $ rootScope.loading = true; -> khi $ http.get kết thúc.


2

Chia sẻ phiên bản câu trả lời tuyệt vời của tôi từ @bulltorious, được cập nhật cho các bản dựng góc cạnh mới hơn (tôi đã sử dụng phiên bản 1.5.8 với mã này) và cũng kết hợp ý tưởng của @ JMaylin về việc sử dụng bộ đếm để mạnh mẽ cho nhiều yêu cầu đồng thời và tùy chọn bỏ qua hiển thị hình động cho các yêu cầu mất ít hơn số mili giây tối thiểu:

var app = angular.module('myApp');
var BUSY_DELAY = 1000; // Will not show loading graphic until 1000ms have passed and we are still waiting for responses.

app.config(function ($httpProvider) {
  $httpProvider.interceptors.push('busyHttpInterceptor');
})
  .factory('busyHttpInterceptor', ['$q', '$timeout', function ($q, $timeout) {
    var counter = 0;
    return {
      request: function (config) {
        counter += 1;
        $timeout(
          function () {
            if (counter !== 0) {
              angular.element('#busy-overlay').show();
            }
          },
          BUSY_DELAY);
        return config;
      },
      response: function (response) {
        counter -= 1;
        if (counter === 0) {
          angular.element('#busy-overlay').hide();
        }
        return response;
      },
      requestError: function (rejection) {
        counter -= 1;
        if (counter === 0) {
          angular.element('#busy-overlay').hide();
        }
        return rejection;
      },
      responseError: function (rejection) {
        counter -= 1;
        if (counter === 0) {
          angular.element('#busy-overlay').hide();
        }
        return rejection;
      }
    }
  }]);

2

Bạn có thể sử dụng thiết bị chặn góc để quản lý các cuộc gọi yêu cầu http

  <div class="loader">
    <div id="loader"></div>
  </div>

<script>
    var app = angular.module("myApp", []);

    app.factory('httpRequestInterceptor', ['$rootScope', '$location', function ($rootScope, $location) {
        return {
            request: function ($config) {
                $('.loader').show();
                return $config;
            },
            response: function ($config) {
                $('.loader').hide();
                return $config;
            },
            responseError: function (response) {
                return response;
            }
        };
    }]);

    app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
        function ($stateProvider, $urlRouterProvider, $httpProvider) {
            $httpProvider.interceptors.push('httpRequestInterceptor');
        }]);

</script>

https://stackoverflow.com/a/49632155/4976786


2

Cách đơn giản mà không cần chặn hoặc jQuery

Đây là một cách đơn giản để hiển thị một công cụ quay vòng không yêu cầu thư viện, bộ chặn hoặc jQuery của bên thứ ba.

Trong bộ điều khiển, đặt và đặt lại một cờ.

function starting() {
    //ADD SPINNER
    vm.starting = true;
    $http.get(url)
      .then(function onSuccess(response) {
        vm.data = response.data;
    }).catch(function onReject(errorResponse) {
        console.log(errorResponse.status);
    }).finally(function() {
        //REMOVE SPINNER
        vm.starting = false;
    });
};

Trong HTML, sử dụng cờ:

<div ng-show="vm.starting">
    <img ng-src="spinnerURL" />
</div>

<div ng-hide="vm.starting">
    <p>{{vm.data}}</p>
</div>

Các vm.startingcờ được thiết lập truekhi XHR bắt đầu và xóa khi chạy xong XHR.


1

Công việc này tốt cho tôi:

HTML:

  <div id="loader" class="ng-hide" ng-show="req.$$state.pending">
    <img class="ajax-loader" 
         width="200" 
         height="200" 
         src="/images/spinner.gif" />
  </div>

Góc cạnh:

  $scope.req = $http.get("/admin/view/"+id).success(function(data) {          
      $scope.data = data;
  });

Trong khi lời hứa được trả lại từ $ http đang chờ xử lý, ng-show sẽ đánh giá nó là "sự thật". Điều này được tự động cập nhật sau khi lời hứa được giải quyết ... đó chính xác là những gì chúng ta muốn.


Đây không phải là cách năng động để làm điều đó.
Umair Hamid

Bạn có thể vui lòng giải thích lý do tại sao bạn tin rằng đây không phải là một cách năng động để đạt được mục tiêu này. Điều này sẽ giúp những người khác đọc bài viết này tìm hiểu. Cảm ơn bạn.
dank

Tôi có nhiều yêu cầu trong ứng dụng của tôi. $ scope.req sẽ chỉ hoạt động cho một yêu cầu duy nhất. Khi yêu cầu cụ thể này, trình tải hoàn chỉnh sẽ ẩn và sẽ không chờ hoàn thành các yêu cầu khác. Cách tốt nhất để đạt được điều này là sử dụng các thiết bị đánh chặn.
Umair Hamid

1

Được sử dụng sau đây để hiển thị thanh tải theo yêu cầu http

'use strict';
appServices.factory('authInterceptorService', ['$q', '$location', 'localStorage','$injector','$timeout', function ($q, $location, localStorage, $injector,$timeout) {

var authInterceptorServiceFactory = {};
var requestInitiated;

//start loading bar
var _startLoading = function () {
   console.log("error start loading");
   $injector.get("$ionicLoading").show();

}

//stop loading bar
var _stopLoading = function () {
    $injector.get("$ionicLoading").hide();
}

//request initiated
var _request = function (config) {
     requestInitiated = true;
    _startLoading();
    config.headers = config.headers || {};
    var authDataInitial = localStorage.get('authorizationData');
    if (authDataInitial && authDataInitial.length > 2) {
        var authData = JSON.parse(authDataInitial);
        if (authData) {
            config.headers.Authorization = 'Bearer ' + authData.token;
        }
    }
    return config;
}

//request responce error
var _responseError = function (rejection) {
   _stopLoading();
    if (rejection.status === 401) {
        $location.path('/login');
    }
    return $q.reject(rejection);
}

//request error
var _requestError = function (err) {
   _stopLoading();
   console.log('Request Error logging via interceptor');
   return err;
}

//request responce
var _response = function(response) {
    requestInitiated = false;

   // Show delay of 300ms so the popup will not appear for multiple http request
   $timeout(function() {

        if(requestInitiated) return;
        _stopLoading();
        console.log('Response received with interceptor');

    },300);

return response;
}



authInterceptorServiceFactory.request = _request;
authInterceptorServiceFactory.responseError = _responseError;
authInterceptorServiceFactory.requestError = _requestError;
authInterceptorServiceFactory.response = _response;

return authInterceptorServiceFactory;
}]);

0
.factory('authHttpResponseInterceptor', ['$q', function ($q) {
        return {
            request: function(config) {
                angular.element('#spinner').show();
                return config;
            },
            response : function(response) {
                angular.element('#spinner').fadeOut(3000);
                return response || $q.when(response);
            },
            responseError: function(reason) {
                angular.element('#spinner').fadeOut(3000);
                return $q.reject(reason);
            }
        };
    }]);



 .config(['$routeProvider', '$locationProvider', '$translateProvider', '$httpProvider',
            function ($routeProvider, $locationProvider, $translateProvider, $httpProvider) {
                $httpProvider.interceptors.push('authHttpResponseInterceptor');
    }
]);

in your Template
<div id="spinner"></div>


css   

#spinner,
#spinner:after {
  border-radius: 50%;
  width: 10em;
  height: 10em;
  background-color: #A9A9A9;
  z-index: 10000;
  position: absolute;
  left: 50%;
  bottom: 100px;
}
@-webkit-keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

1
Câu trả lời chỉ có mã không hữu ích lắm.
Phantômaxx

0

tạo chỉ thị với mã này:

$scope.$watch($http.pendingRequests, toggleLoader);

function toggleLoader(status){
  if(status.length){
    element.addClass('active');
  } else {
    element.removeClass('active');
  }
}

0

Một giải pháp khác để hiển thị tải giữa các thay đổi url khác nhau là:

$rootScope.$on('$locationChangeStart', function() {
  $scope.loading++;
});

$rootScope.$on('$locationChangeSuccess', function() {
  $timeout(function() {
    $scope.loading--;
  }, 300);
});

Và sau đó trong đánh dấu chỉ cần chuyển đổi spinner với ng-show="loading".

Nếu bạn muốn hiển thị nó trên các yêu cầu ajax, chỉ cần thêm $scope.loading++khi yêu cầu bắt đầu và khi nó kết thúc thêm $scope.loading--.


0

Bạn cũng có thể thử một cái gì đó như thế này:

Tạo chỉ thị:

myApp.directive('loader', function () {
    return {
        restrict: 'A',
        scope: {cond: '=loader'},
        template: '<span ng-if="isLoading()" class="soft"><span class="fa fa-refresh fa-spin"></span></span>',
        link: function (scope) {
            scope.isLoading = function() {
                var ret = scope.cond === true || (
                        scope.cond &&
                        scope.cond.$$state &&
                        angular.isDefined(scope.cond.$$state.status) &&
                        scope.cond.$$state.status === 0
                    );
                return ret;
            }
        }
    };
}); 

Sau đó, bạn thêm một cái gì đó như thế này vào mainCtrl

    // Return TRUE if some request is LOADING, else return FALSE
    $scope.isLoading = function() {
        return $http.pendingRequests.length > 0;
    };

Và HTML có thể trông như thế này:

<div class="buttons loader">
    <span class="icon" loader="isLoading()"></span>
</div>

0

Cách sau đây sẽ ghi chú tất cả các yêu cầu và chỉ ẩn sau khi tất cả các yêu cầu được thực hiện:

app.factory('httpRequestInterceptor', function(LoadingService, requestCount) {
    return {
        request: function(config) {
            if (!config.headers.disableLoading) {
                requestCount.increase();
                LoadingService.show();
            }
            return config;
        }
    };
}).factory('httpResponseInterceptor', function(LoadingService, $timeout, error, $q, requestCount) {
    function waitAndHide() {
        $timeout(function() {
            if (requestCount.get() === 0){
                LoadingService.hide();
            }
            else{
                waitAndHide();
            }
        }, 300);
    }

    return {
        response: function(config) {
            requestCount.descrease();
            if (requestCount.get() === 0) {
                waitAndHide();
            }
            return config;
        },
        responseError: function(config) {
            requestCount.descrease();
            if (requestCount.get() === 0) {
                waitAndHide();
            }
            var deferred = $q.defer();
            error.show(config.data, function() {
                deferred.reject(config);
            });
            return deferred.promise;
        }
    };
}).factory('requestCount', function() {
    var count = 0;
    return {
        increase: function() {
            count++;
        },
        descrease: function() {
            if (count === 0) return;
            count--;
        },
        get: function() {
            return count;
        }
    };
})


0

Do chức năng của vị trí: đã cố định thay đổi gần đây, tôi gặp khó khăn khi hiển thị trình tải gif trên tất cả các phần tử, vì vậy tôi phải sử dụng jQuery sẵn có của angular .

Html

<div ng-controller="FetchController">
      <div id="spinner"></div>
</div>

Css

#spinner {display: none}
body.spinnerOn #spinner { /* body tag not necessary actually */
   display: block;
   height: 100%;
   width: 100%;
   background: rgba(207, 13, 48, 0.72) url(img/loader.gif) center center no-repeat;
   position: fixed;
   top: 0;
   left: 0;
   z-index: 9999;
}
body.spinnerOn main.content { position: static;} /* and whatever content needs to be moved below your fixed loader div */

Bộ điều khiển

app.controller('FetchController', ['$scope', '$http', '$templateCache', '$location', '$q',
function($scope, $http, $templateCache, $location, $q) {

angular.element('body').addClass('spinnerOn'); // add Class to body to show spinner

$http.post( // or .get(
    // your data here
})
.then(function (response) {
    console.info('success');     
    angular.element('body').removeClass('spinnerOn'); // hide spinner

    return response.data;               
}, function (response) {                   
    console.info('error'); 
    angular.element('body').removeClass('spinnerOn'); // hide spinner
});

})

Hi vọng điêu nay co ich :)


0

Tất cả các câu trả lời là hoặc phức tạp, hoặc cần đặt một số biến cho mỗi yêu cầu, đó là cách thực hành rất sai nếu chúng ta biết khái niệm DRY. Ở đây ví dụ đánh chặn đơn giản, tôi đặt chuột chờ khi ajax khởi động và đặt nó thành tự động khi ajax kết thúc.

$httpProvider.interceptors.push(function($document) {
    return {
     'request': function(config) {
         // here ajax start
         // here we can for example add some class or show somethin
         $document.find("body").css("cursor","wait");

         return config;
      },

      'response': function(response) {
         // here ajax ends
         //here we should remove classes added on request start

         $document.find("body").css("cursor","auto");

         return response;
      }
    };
  });

Mã phải được thêm vào trong cấu hình ứng dụng app.config. Tôi đã chỉ cho bạn cách thay đổi chuột khi tải trạng thái nhưng trong đó có thể hiển thị / ẩn bất kỳ nội dung trình tải nào hoặc thêm, xóa một số lớp css đang hiển thị trình tải.

Bộ chặn sẽ chạy trên mọi cuộc gọi ajax, do đó không cần tạo các biến boolean đặc biệt ($ scope.loading = true / false, v.v.) trên mỗi cuộc gọi http.


0

Đây là cách thực hiện của tôi, đơn giản như ng-show và bộ đếm yêu cầu.

Nó sử dụng một dịch vụ mới cho tất cả các yêu cầu tới $ http:

myApp.service('RqstSrv', [ '$http', '$rootScope', function($http, $rootScope) {
    var rqstService = {};

    rqstService.call = function(conf) {

        $rootScope.currentCalls = !isNaN($rootScope.currentCalls) ?  $rootScope.currentCalls++ : 0;

        $http(conf).then(function APICallSucceed(response) {
            // Handle success
        }, function APICallError(response) {
            // Handle error
        }).then(function() {
            $rootScope.currentCalls--;
        });
    }
} ]);

Và sau đó bạn có thể sử dụng cơ sở bộ tải của mình dựa trên số lượng cuộc gọi hiện tại:

<img data-ng-show="currentCalls > 0" src="images/ajax-loader.gif"/>

0

nếu bạn muốn hiển thị trình tải cho mỗi cuộc gọi yêu cầu http thì bạn có thể sử dụng bộ chặn góc để quản lý các cuộc gọi yêu cầu http,

đây là một mã mẫu

<body data-ng-app="myApp">
<div class="loader">
    <div id="loader"></div>
</div>

<script>
    var app = angular.module("myApp", []);

    app.factory('httpRequestInterceptor', ['$rootScope', '$location', function ($rootScope, $location) {
        return {
            request: function ($config) {
                $('.loader').show();
                return $config;
            },
            response: function ($config) {
                $('.loader').hide();
                return $config;
            },
            responseError: function (response) {
                return response;
            }
        };
    }]);

    app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
        function ($stateProvider, $urlRouterProvider, $httpProvider) {
            $httpProvider.interceptors.push('httpRequestInterceptor');
        }]);

</script>
</body>

0

Chỉ cần sử dụng ng-show và boolean

Không cần sử dụng một chỉ thị, không cần phải phức tạp.

Đây là mã để đặt bên cạnh nút gửi hoặc bất cứ nơi nào bạn muốn spinner là:

<span ng-show="dataIsLoading">
  <img src="http://www.nasa.gov/multimedia/videogallery/ajax-loader.gif" style="height:20px;"/>
</span>

Và sau đó trong bộ điều khiển của bạn:

$scope.dataIsLoading = true

let url = '/whatever_Your_URL_Is'
$http.get(url)
.then(function(response) {
  $scope.dataIsLoading = false
})

-1

Đây là giải pháp của tôi mà tôi cảm thấy là rất nhiều dễ dàng hơn mà người khác đăng ở đây. Không chắc là nó "đẹp" như thế nào, nhưng nó đã giải quyết tất cả các vấn đề của tôi

Tôi có một kiểu css gọi là "đang tải"

.loading { display: none; }

Html cho div tải có thể là bất cứ điều gì nhưng tôi đã sử dụng một số biểu tượng FontAwgie và phương thức quay ở đó:

<div style="text-align:center" ng-class="{ 'loading': !loading }">
    <br />
    <h1><i class="fa fa-refresh fa-spin"></i> Loading data</h1>
</div>

Trên các yếu tố mà bạn muốn ẩn bạn chỉ cần viết này:

<something ng-class="{ 'loading': loading }" class="loading"></something>

và trong chức năng tôi chỉ cần thiết lập điều này trên tải.

(function (angular) {
    function MainController($scope) {
        $scope.loading = true

Tôi đang sử dụng SignalR vì vậy trong chức năng hubProxy.client.allLocks (khi hoàn thành việc đi qua các khóa), tôi sẽ đặt

 $scope.loading = false
 $scope.$apply();

Điều này cũng ẩn {{someField}} khi trang đang tải vì tôi đang thiết lập lớp tải khi tải và AngularJS sẽ xóa nó sau đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.