Показать спиннер GIF во время запроса $ http в AngularJS?


234

Я использую $httpсервис AngularJS, чтобы сделать запрос Ajax.

Как можно отобразить вращающийся GIF (или другой тип индикатора занятости) во время выполнения Ajax-запроса?

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


2
Если вам нужен простой спиннер, основанный на HTTP-перехватчиках, у меня есть угловой модуль для этого. Он использует популярный спиннер Identified Sham. Посмотрите: github.com/harinair/angular-sham-spinner
Хари Гангадхаран

1
Я написал плагин angular-httpshooter , он выпускает событие с данными конфигурации непосредственно перед съемкой вызова и выпускает другое сразу после получения resposne, вы можете написать глобальные загрузчики,
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 после завершения первых запросов.
Микер

38
В соответствии с передовой практикой AngularJS (которую нарушает принятое решение), вам не следует изменять DOM вне директивы. Подумайте о том, чтобы вызвать show / hide для элементов из директивы.
Мариуш

7
Я не уверен, что знаю достаточно, чтобы комментировать ... Но разве не будет правильного способа сделать это, используя ng-classдирективу вместо использования JQuery для показа и скрытия элементов?
Джеймс Хилд

2
@JamesHeald правильно .. вам никогда не нужно использовать jQuery для любых манипуляций с dom в Angular. Посмотрите на: ng-class, ng-if, ng-hide, 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--;. И нечего менять в шаблоне. Таким образом, счетчик отображается, когда выполняется хотя бы один запрос, а остальное время
скрыт

16
Вам, вероятно, следует также установить значение false в функцию возврата к ошибке.
Себнукем

3
@sebnukem Ты прав. Это был довольно высокоуровневый пример, но я все равно добавил его для ясности. Спасибо за ответ!
Джош Дэвид Миллер

1
@JMaylin - затем вы можете использовать $ watch на $ scope.loading для других целей
Jason

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

44

Вот версия с использованием directiveи ng-hide.

Это покажет загрузчик во всех звонках через $httpсервис angular .

В шаблоне:

<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, атрибут $ resolved объекта полезен для загрузчиков:

Для ресурса следующим образом:

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

Вы можете связать загрузчик с атрибутом $ resolved объекта ресурса:

<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

angular-busy только надевает на ваш элемент маску, я не думаю, что вы можете отключить кнопку так, как хотите, но вы можете установить фон на нее с помощью пустого шаблона, чтобы создать такое впечатление. Я не являюсь носителем языка, извините за путаницу :)
Balthazar

Хорошо, я отредактировал ваш ответ, чтобы не допустить такого же замешательства. Франкоязычный английский с другим французским всегда сбивает с толку :)
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;
    });

SPINNER DIRECTIVE

(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 оценит его как «правдивое». Это автоматически обновляется, как только обещание будет выполнено ... это именно то, что мы хотим.


Это не динамичный способ сделать это.
Умайр Хамид

Не могли бы вы объяснить, почему вы считаете, что это не динамичный способ достижения этой цели. Это поможет другим, читающим этот пост, учиться. Спасибо.
промозглый

У меня есть несколько запросов в моем заявлении. $ scope.req будет работать только для одного запроса. При выполнении этого конкретного запроса загрузчик будет скрываться и не будет ждать завершения других запросов. Лучший способ добиться этого - использовать перехватчики.
Umair Хамид

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

Поскольку функциональность position: fixed недавно изменилась, мне было трудно показать gif-загрузчик над всеми элементами, поэтому мне пришлось использовать встроенный в Angular 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

Все ответы являются либо сложными, либо должны устанавливать некоторые переменные для каждого запроса, что является очень неправильной практикой, если мы знаем концепцию СУХОЙ. Вот простой пример перехватчика, я установил мышь на ожидание при запуске 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, поэтому нет необходимости создавать специальные логические переменные ($ scope.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

Просто используйте нг-шоу и логическое значение

Не нужно использовать директиву, не нужно усложнять.

Вот код, который нужно поместить рядом с кнопкой отправки или где вы хотите, чтобы спиннер был:

<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 и метод spin там:

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