Показати спінер GIF під час $ http запиту в AngularJS?


234

Я використовую $http послугу AngularJS, щоб зробити запит на Ajax.

Як може відображатися GIF-спінер (або інший тип індикатора зайнятості) під час виконання запиту Ajax?

Я не бачу нічого подібного ajaxstarteventв документації AngularJS.


2
Якщо ви хочете простий спінер на основі перехоплювачів HTTP, у мене є кутовий модуль для цього. Він використовує популярний прядильний ідентифікований Шам. Подивіться: github.com/harinair/angular-sham-spinner
Харі Гангадхаран

1
Я написав плагін angular-httpshooter , він випускає подію з конфігураційними даними безпосередньо перед зйомкою виклику та випускає іншу, відразу після отримання зворотної зйомки, ви можете писати глобальні навантажувачі, що ловлять ці події
Siddharth

Відповіді:


88

Ось нинішні заклики AngularJS:

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']).
//.......

Ось решта (HTML / CSS) .... використовуючи

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

щоб переключити його. ПРИМІТКА: вищевказане використовується в кутовому модулі на початку публікації

#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
Зауважте, що ви можете використовувати angular.element('#mydiv').show()замість$('#mydiv').show()
JMaylin

8
це не працює, якщо на вашій сторінці подано кілька запитів на ajax. Він приховає gif завантаження після закінчення перших запитів.
Meeker

38
Відповідно до кращих практик AngularJS (які прийняте рішення порушує), ви не повинні змінювати DOM поза директивою. Подумайте про те, щоб викликати показ / приховування елементів із директиви.
Маріуш

7
Я не впевнений, що знаю достатньо, щоб прокоментувати ... Але хіба не правильним шляхом робити це використання ng-classдирективи, а не використання JQuery для показу та приховування елементів?
Джеймс Хілд

2
@JamesHeald вірно .. ніколи вам ніколи не потрібно використовувати jQuery для будь-яких маніпуляцій домом у Angular. Погляньте на: ng-class, ng-if, ng-hid, ng-show тощо. Є директива щодо майже всього, що вам коли-небудь знадобиться.
jKlaus

471

Це дійсно залежить від конкретного випадку використання, але простий спосіб слід за такою схемою:

.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;
  });
});

А потім реагуйте на це у своєму шаблоні:

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

223
Якщо у вас є кілька запитів ajax одночасно, ви можете оголосити loadingяк ціле число $scope.loading = 0;, коли запит починається з вас $scope.loading++;і коли він закінчується $scope.loading--;. І в шаблоні нічого змінити. Тож спінер виводиться, коли є хоча б один запит, і решту часу приховано
JMaylin

16
Ви, ймовірно, повинні встановити значення false у функції резервного помилки.
sebnukem

3
@sebnukem Право ти є. Це був досить високий приклад, але я продовжував додавати це для ясності. Дякуємо за відгук!
Джош Девід Міллер

1
@JMaylin - ви можете використовувати $ watch на $ range.loading робити інші речі
Джейсон

5
Ще більш чистим способом, замість того, щоб застосовувати $scope.loading = falseяк успіх, так і зворотний виклик, є встановити його в .finally(). Це буде виглядати так:mySvc.get().then(success, fail).finally(function() { $scope.loading = false; });
Том

44

Ось версія з використанням directiveта ng-hide.

Це покаже навантажувач під час усіх дзвінків за допомогою послуги кутового $http.

У шаблоні:

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

директива:

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');
          }
        });
      }
    };
}]);

використовуючи ng-hideклас на елементі, ви можете уникнути jquery.


Налаштувати: додати interceptor

Якщо ви створюєте завантажувальний перехоплювач, ви можете показати / приховати завантажувач на основі умови.

директива:

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');
      });
  };
};

перехоплювач:

  • наприклад: не показувати, spinnerколиresponse.background === true;
  • Перехоплення requestта / або responseвстановлення $rootScope.$broadcast("loader_show");або$rootScope.$broadcast("loader_hide");

більше інформації про написання перехоплювача


@punkrockpolly У моєму конкретному сценарії у мене є два окремі компоненти, які викликають службу. Але це просто працює для одного з них. Чи потрібно пройти параметр чи щось, щоб зробити це багаторазовим?
Рікардо Гонзалес

@razorblade, він повернеться в будь-який час, коли ви телефонуєте через $httpбудь-яку службу.
punkrockpolly

31

Якщо ви використовуєте ngResource, атрибут $ object об'єкта корисний для завантажувачів:

Для ресурсу наступним чином:

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

Ви можете зв’язати завантажувач з атрибутом $ разрешеного ресурсу об'єктом:

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


13

Щойно виявив angular-busyдирективу, яка показує невеликий завантажувач залежно від деякого виклику асинхронізації.

Наприклад, якщо вам доведеться виконати GET, посилайтеся на свою обіцянку $scope,

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

і називайте це так:

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

Ось GitHub.

Ви також можете встановити його за допомогою bower(не забудьте оновити залежність проекту):

bower install angular-busy --save

Не вдалося знайти, як «відключити якийсь елемент» у документації. Чи можете ви пояснити, як? Наприклад, я хочу відключити кнопку під час показу спинера.
c4k

Кутовий зайнятий лише надягайте на ваш елемент маску, я не думаю, що ви можете відключити кнопку так, як хочете, але ви можете встановити задній фон із порожнім шаблоном, щоб створити таке враження. Я не носій мови, вибачте за плутанину :)
Бальтазар,

Гаразд, я відредагував вашу відповідь, щоб у когось іншого не було такого ж плутанини. Французька, що розмовляє англійською на іншій французькій, завжди плутає :)
c4k

5

Якщо ви обробляєте дзвінки api в рамках послуги / фабрики, ви можете відстежувати там лічильник завантаження (за кожну відповідь та відмінна одночасна пропозиція від @JMaylin) та посилатись на лічильник завантаження за допомогою директиви. Або будь-яка їх комбінація.

API WRAPPER

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

ДИРЕКТИВА СПІНЕРА

(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);

ВИКОРИСТАННЯ

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

5

Для завантаження сторінок і модалів найпростішим способом є використання ng-showдирективи та використання однієї зі змінних даних про область застосування. Щось на зразок:

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

Тут, поки someObjectне визначено, покаже спінер. Як тільки служба повертається з даними та someObjectзаповнюється, спінер повернеться до свого прихованого стану.


3

Це найпростіший спосіб додати спінер, я думаю:

Ви можете використовувати ng-show з тегом div будь-якого з цих прекрасних спінерів http://tobiasahlin.com/spinkit/ {{Це не моя сторінка}}

і тоді ви можете використовувати таку логіку

//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>

Додати цей css:

    .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;
}

І просто у вашому кутовому дописі:

$ rootScope.loading = false; $ rootScope.loading = true; -> коли $ http.get закінчується.


2

Поділився моєю версією чудового відповіді від @bulltorious, оновленої для новіших кутових збірок (я використовував версію 1.5.8 з цим кодом), а також включив ідею @ JMaylin використовувати лічильник, щоб бути надійним для декількох одночасних запитів, і можливість пропустити показ анімації для запитів, що займають менше деякої мінімальної кількості мілісекунд:

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

Ви можете використовувати кутовий перехоплювач для керування дзвінками із запитом 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

Простий спосіб без перехоплювачів або jQuery

Це простий спосіб показати спінер, який не вимагає сторонньої бібліотеки, перехоплювачів або jQuery.

У контролері встановіть і скиньте прапор.

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

У HTML використовуйте прапор:

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

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

vm.startingПрапор встановлюється , trueколи XHR починається і очищається , коли XHR НЕ завершиться.


1

Це добре для мене:

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>

Кутовий:

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

Поки обіцянка, повернута з $ http, очікує на очікування, ng-show оцінить її як "правду". Це автоматично оновлюється, коли обіцянка буде вирішена ... саме цього ми хочемо.


Це не динамічний спосіб зробити це.
Умаїр Хамід

Чи можете ви поясніть, чому ви вважаєте, що це не динамічний спосіб досягнення цієї мети. Це допоможе оточуючим читати цю публікацію. Дякую.
данк

У моїй заявці є декілька запитів. $ range.req працюватиме лише для одного запиту. Коли цей конкретний запит, повний завантажувач буде схований і не чекатиме завершення інших запитів. Найкращий спосіб досягти цього - використовувати перехоплювачі.
Умаїр Хамід

1

Використовується наступний перехоплювач для відображення панелі завантаження на запит 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
Відповіді лише на код не дуже корисні.
Phantômaxx

0

створити директиву з цим кодом:

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

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

0

Ще одне рішення показати завантаження між різними змінами URL:

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

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

А потім у розмітці просто перемкніть прядильник ng-show="loading".

Якщо ви хочете відобразити його на запитах ajax, просто додайте, $scope.loading++коли запит починається і коли він закінчується, додайте $scope.loading--.


0

Ви також можете спробувати щось подібне:

Створити директиву:

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

Потім ви додаєте щось подібне до mainCtrl

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

І HTML може виглядати так:

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

0

Наступний спосіб буде враховувати всі запити та приховувати лише після того, як всі запити будуть виконані:

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

Оскільки функціональність позиції: фіксований нещодавно змінився, у мене виникли труднощі із відображенням завантажувача gif над усіма елементами, тому мені довелося використовувати вбудований jQuery з кутового .

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 */

Контролер

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

})

Сподіваюся, це допомагає :)


0

Усі відповіді є або складними, або потрібно встановлювати деякі змінні на кожен запит, що є дуже неправильною практикою, якщо ми знаємо концепцію DRY. Наведемо простий приклад перехоплювача, я вмикаю мишу в очікуванні, коли починається ajax, і встановлюю її автоматично, коли ajax закінчується.

$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;
      }
    };
  });

Код потрібно додати в конфігурацію програми app.config. Я показав, як змінити мишу в стані завантаження, але там можна показати / приховати будь-який вміст завантажувача або додати, видалити деякі класи css, які показують завантажувач.

Перехоплювач виконуватиме кожен виклик ajax, тому не потрібно створювати спеціальні булеві змінні ($ range.loading = true / false тощо) на кожному http-дзвінку.


0

Ось моя реалізація, така ж проста, як ng-show та лічильник запитів.

Він використовує нову послугу для всіх запитів на $ 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--;
        });
    }
} ]);

Після цього ви можете використовувати базу завантажувача на кількість поточних дзвінків:

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

0

якщо ви хочете показати завантажувач для кожного дзвінка з запитом на http, тоді ви можете використовувати кутовий перехоплювач для керування дзвінками з запитом http,

ось зразок коду

<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

Просто використовуйте ng-show і булевий

Не потрібно використовувати директиву, не потрібно ускладнюватися.

Ось код, який слід поставити поруч із кнопкою для надсилання або там, де ви хочете, щоб прядок був:

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

А потім у своєму контролері:

$scope.dataIsLoading = true

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

-1

Ось моє рішення, яке я відчуваю, набагато легше, ніж інші, розміщені тут. Не впевнений, наскільки це "досить", але це вирішило всі мої питання

У мене стиль css називається "завантаження"

.loading { display: none; }

HTML для завантажувального div може бути будь-яким, але я використовував деякі піктограми FontAwesome та метод віджимання:

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

На елементах, які ви хочете приховати, просто напишіть це:

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

і в функції я просто встановив це на навантаження.

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

Я використовую SignalR, тому у функції hubProxy.client.allLocks (коли це робиться через замки), я покладу

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

Це також приховує {{someField}}, коли сторінка завантажується, оскільки я встановлюю клас завантаження на завантаження, і AngularJS видаляє його згодом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.