Angularjs carregando a canvas no pedido de ajax

Usando o Angularjs, eu preciso mostrar uma canvas de carregamento (um simples spinner) até que a requisição do ajax esteja completa. Por favor, sugira qualquer ideia com um trecho de código.

Em vez de configurar uma variável de escopo para indicar o status do carregamento de dados, é melhor que uma diretiva faça tudo para você:

 angular.module('directive.loading', []) .directive('loading', ['$http' ,function ($http) { return { restrict: 'A', link: function (scope, elm, attrs) { scope.isLoading = function () { return $http.pendingRequests.length > 0; }; scope.$watch(scope.isLoading, function (v) { if(v){ elm.show(); }else{ elm.hide(); } }); } }; }]); 

Com esta diretiva, tudo o que você precisa fazer é dar a qualquer elemento de animação de carregamento um atributo ‘loading’:

 

Você pode ter vários spinners de carregamento na página. onde e como layout esses spinners é com você e directiva irá simplesmente ligar / desligar para você automaticamente.

Aqui está um exemplo. Ele usa o método ng-show simples com um bool.

HTML

 
LOADINGhttps://stackoverflow.com/questions/17144180/angularjs-loading-screen-on-ajax-request/...
  • {{car.name}}
  • ANGULARJS

      $scope.clickMe = function() { $scope.loading = true; $http.get('test.json') .success(function(data) { $scope.cars = data[0].cars; $scope.loading = false; }); } 

    É claro que você pode mover o código html da checkbox de carregamento para uma diretiva e, em seguida, usar $ watch em $ scope.loading. Nesse caso:

    HTML :

      

    DIRECTIVA ANGULARJS :

      .directive('loading', function () { return { restrict: 'E', replace:true, template: '
    LOADINGhttps://stackoverflow.com/questions/17144180/angularjs-loading-screen-on-ajax-request/...
    ', link: function (scope, element, attr) { scope.$watch('loading', function (val) { if (val) $(element).show(); else $(element).hide(); }); } } })

    PLUNK : http://plnkr.co/edit/AI1z21?p=preview

    Eu uso o ngProgress para isso.

    Adicione ‘ngProgress’ às suas dependencies depois de include os arquivos script / css no seu HTML. Depois de fazer isso, você pode configurar algo assim, que será acionado quando uma alteração de rota for detectada.

     angular.module('app').run(function($rootScope, ngProgress) { $rootScope.$on('$routeChangeStart', function(ev,data) { ngProgress.start(); }); $rootScope.$on('$routeChangeSuccess', function(ev,data) { ngProgress.complete(); }); }); 

    Para pedidos de AJAX, você pode fazer algo assim:

     $scope.getLatest = function () { ngProgress.start(); $http.get('/latest-goodies') .success(function(data,status) { $scope.latest = data; ngProgress.complete(); }) .error(function(data,status) { ngProgress.complete(); }); }; 

    Apenas lembre-se de adicionar ‘ngProgress’ às dependencies dos controllers antes de fazer isso. E se você estiver fazendo várias solicitações AJAX, use uma variável incremental no escopo do aplicativo principal para acompanhar quando suas solicitações AJAX tiverem terminado antes de chamar ‘ngProgress.complete ();’.

    O uso de pendingRequests não está correto porque, como mencionado na documentação Angular, essa propriedade é usada principalmente para fins de debugging.

    O que eu recomendo é usar um interceptador para saber se existe alguma chamada Assíncrona ativa.

     module.config(['$httpProvider', function ($httpProvider) { $httpProvider.interceptors.push(function ($q, $rootScope) { if ($rootScope.activeCalls == undefined) { $rootScope.activeCalls = 0; } return { request: function (config) { $rootScope.activeCalls += 1; return config; }, requestError: function (rejection) { $rootScope.activeCalls -= 1; return rejection; }, response: function (response) { $rootScope.activeCalls -= 1; return response; }, responseError: function (rejection) { $rootScope.activeCalls -= 1; return rejection; } }; }); }]); 

    e então verifique se o activeCalls é zero ou não na diretiva através de um $ watch.

     module.directive('loadingSpinner', function ($http) { return { restrict: 'A', replace: true, template: '
    ', link: function (scope, element, attrs) { scope.$watch('activeCalls', function (newVal, oldVal) { if (newVal == 0) { $(element).hide(); } else { $(element).show(); } }); } }; });

    A melhor maneira de fazer isso é usar interceptores de resposta junto com a diretiva personalizada. E o processo pode ser melhorado usando o mecanismo pub / sub usando $ rootScope. $ Broadcast & $ rootScope. $ Em methods.

    Como todo o processo está documentado em um artigo de blog bem escrito, não vou repetir isso aqui novamente. Por favor, consulte esse artigo para chegar a sua implementação necessária.

    Em referência desta resposta

    https://stackoverflow.com/a/17144634/4146239

    Para mim é a melhor solução, mas há uma maneira de evitar o uso do jQuery.

     .directive('loading', function () { return { restrict: 'E', replace:true, template: '
    LOADINGhttps://stackoverflow.com/questions/17144180/angularjs-loading-screen-on-ajax-request/...
    ', link: function (scope, element, attr) { scope.$watch('loading', function (val) { if (val) scope.loadingStatus = 'true'; else scope.loadingStatus = 'false'; }); } } }) .controller('myController', function($scope, $http) { $scope.cars = []; $scope.clickMe = function() { scope.loadingStatus = 'true' $http.get('test.json') .success(function(data) { $scope.cars = data[0].cars; $scope.loadingStatus = 'false'; }); } });
       
  • {{car.name}}
  • Implementação Datilografada e Angular

    diretiva

     ((): void=> { "use strict"; angular.module("app").directive("busyindicator", busyIndicator); function busyIndicator($http:ng.IHttpService): ng.IDirective { var directive = { restrict: "A", link(scope: Scope.IBusyIndicatorScope) { scope.anyRequestInProgress = () => ($http.pendingRequests.length > 0); scope.$watch(scope.anyRequestInProgress, x => { if (x) { scope.canShow = true; } else { scope.canShow = false; } }); } }; return directive; } })(); 

    Escopo

      module App.Scope { export interface IBusyIndicatorScope extends angular.IScope { anyRequestInProgress: any; canShow: boolean; } } 

    Modelo

     
    CSS #activityspinner { display : none; } #activityspinner.show { display : block; position : fixed; z-index: 100; background-image : url('data:image/gif;base64,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') -ms-opacity : 0.4; opacity : 0.4; background-repeat : no-repeat; background-position : center; left : 0; bottom : 0; right : 0; top : 0; }

    Também há uma boa demonstração que mostra como você pode usar a animação Angularjs em seu projeto.
    o link está aqui
    http://yearofmoo-articles.github.io/angularjs-animation-article/app/#/ng-repeat (Veja o canto superior esquerdo) .
    É uma fonte aberta. aqui está o link para baixar
    https://github.com/yearofmoo-articles/AngularJS-Animation-Article
    E aqui está o link para o tutorial;
    http://www.yearofmoo.com/2013/04/animation-in-angularjs.html
    Meu ponto é, vá em frente e baixar os arquivos de origem e, em seguida, ver como eles implementaram o spinner. Eles podem ter usado uma abordagem um pouco melhor. Então, confira este projeto.

    Se você estiver usando Restangular (o que é incrível), você pode criar uma animação durante as chamadas da API. Aqui está a minha solução. Adicione um interceptador de resposta e um interceptador de solicitação que envia uma transmissão do rootscope. Em seguida, crie uma diretiva para ouvir essa resposta e solicitação:

      angular.module('mean.system') .factory('myRestangular',['Restangular','$rootScope', function(Restangular,$rootScope) { return Restangular.withConfig(function(RestangularConfigurer) { RestangularConfigurer.setBaseUrl('http://localhost:3000/api'); RestangularConfigurer.addResponseInterceptor(function(data, operation, what, url, response, deferred) { var extractedData; // .. to look for getList operations if (operation === 'getList') { // .. and handle the data and meta data extractedData = data.data; extractedData.meta = data.meta; } else { extractedData = data.data; } $rootScope.$broadcast('apiResponse'); return extractedData; }); RestangularConfigurer.setRequestInterceptor(function (elem, operation) { if (operation === 'remove') { return null; } return (elem && angular.isObject(elem.data)) ? elem : {data: elem}; }); RestangularConfigurer.setRestangularFields({ id: '_id' }); RestangularConfigurer.addRequestInterceptor(function(element, operation, what, url) { $rootScope.$broadcast('apiRequest'); return element; }); }); }]); 

    Aqui está a diretiva:

      angular.module('mean.system') .directive('smartLoadingIndicator', function($rootScope) { return { restrict: 'AE', template: '

     Loading

    ', replace: true, link: function(scope, elem, attrs) { scope.isAPICalling = false; $rootScope.$on('apiRequest', function() { scope.isAPICalling = true; }); $rootScope.$on('apiResponse', function() { scope.isAPICalling = false; }); } }; }) ;

    Inclua isso no seu “app.config”:

      $httpProvider.interceptors.push('myHttpInterceptor'); 

    E adicione este código:

     app.factory('myHttpInterceptor', function ($q, $window,$rootScope) { $rootScope.ActiveAjaxConectionsWithouthNotifications = 0; var checker = function(parameters,status){ //YOU CAN USE parameters.url TO IGNORE SOME URL if(status == "request"){ $rootScope.ActiveAjaxConectionsWithouthNotifications+=1; $('#loading_view').show(); } if(status == "response"){ $rootScope.ActiveAjaxConectionsWithouthNotifications-=1; } if($rootScope.ActiveAjaxConectionsWithouthNotifications<=0){ $rootScope.ActiveAjaxConectionsWithouthNotifications=0; $('#loading_view').hide(); } }; return { 'request': function(config) { checker(config,"request"); return config; }, 'requestError': function(rejection) { checker(rejection.config,"request"); return $q.reject(rejection); }, 'response': function(response) { checker(response.config,"response"); return response; }, 'responseError': function(rejection) { checker(rejection.config,"response"); return $q.reject(rejection); } }; }); 

    Use ocupado angular :

    Adicione o cgBusy ao seu aplicativo / módulo:

     angular.module('your_app', ['cgBusy']); 

    Adicione sua promise ao scope :

     function MyCtrl($http, User) { //using $http this.isBusy = $http.get('https://stackoverflow.com/questions/17144180/angularjs-loading-screen-on-ajax-request/...'); //if you have a User class based on $resource this.isBusy = User.$save(); } 

    Em seu modelo de html:

     

    Aqui exemplo de interceptador simples, eu coloco o mouse em espera quando o ajax inicia e o defino como automático quando o ajax termina.

     $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 classs added on request start $document.find("body").css("cursor","auto"); return response; } }; }); 

    O código deve ser adicionado na configuração do aplicativo app.config . Eu mostrei como alterar o mouse no estado de carregamento, mas lá é possível mostrar / ocultar qualquer conteúdo do carregador, ou adicionar, remover algumas classs css que estão mostrando o carregador.

    O Interceptor será executado em todas as chamadas ajax, portanto não há necessidade de criar variables ​​booleanas especiais ($ scope.loading = true / false etc.) em todas as chamadas http.

    O Interceptor está usando o build construído em jqLite angular https://docs.angularjs.org/api/ng/function/angular.element, portanto, não é necessário ter o Jquery.

    Crie uma diretiva com os atributos de show e tamanho (você também pode adicionar mais)

      app.directive('loader',function(){ return { restrict:'EA', scope:{ show : '@', size : '@' }, template : '
    ' } })

    e em html use como

       

    Na variável show , passe true quando qualquer promise estiver sendo executada e torne isso falso quando a solicitação for concluída. Demonstração ativa – Exemplo de demonstração da diretiva do carregador angular no JsFiddle

    Eu construí sobre a resposta do @ DavidLin um pouco para simplificar – removendo qualquer dependência do jQuery na diretiva. Eu posso confirmar isso funciona como eu uso em um aplicativo de produção

     function AjaxLoadingOverlay($http) { return { restrict: 'A', link: function ($scope, $element, $attributes) { $scope.loadingOverlay = false; $scope.isLoading = function () { return $http.pendingRequests.length > 0; }; $scope.$watch($scope.isLoading, function (isLoading) { $scope.loadingOverlay = isLoading; }); } }; } 

    Eu uso um ng-show vez de uma chamada jQuery para esconder / mostrar o

    .

    Aqui está o

    que eu coloquei logo abaixo da tag abertura:

     

    E aqui está o CSS que fornece a sobreposição para bloquear a interface do usuário enquanto uma chamada $ http está sendo feita:

     .loading-overlay { position: fixed; z-index: 999; height: 2em; width: 2em; overflow: show; margin: auto; top: 0; left: 0; bottom: 0; right: 0; } .loading-overlay:before { content: ''; display: block; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.3); } /* :not(:required) hides these rules from IE9 and below */ .loading-overlay:not(:required) { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; } 

    Crédito CSS vai para @Steve Seeger’s – seu post: https://stackoverflow.com/a/35470281/335545

    Você pode adicionar uma condição e, em seguida, alterá-lo através do rootscope. Antes do seu pedido de ajax, você simplesmente chama $ rootScope. $ Emit (‘stopLoader’);

     angular.module('directive.loading', []) .directive('loading', ['$http', '$rootScope',function ($http, $rootScope) { return { restrict: 'A', link: function (scope, elm, attrs) { scope.isNoLoadingForced = false; scope.isLoading = function () { return $http.pendingRequests.length > 0 && scope.isNoLoadingForced; }; $rootScope.$on('stopLoader', function(){ scope.isNoLoadingForced = true; }) scope.$watch(scope.isLoading, function (v) { if(v){ elm.show(); }else{ elm.hide(); } }); } }; }]); 

    Esta não é definitivamente a melhor solução, mas ainda funciona.