guida - angularjs template




Mostra GIF di Spinner durante la richiesta $ http in angolare (16)

È possibile utilizzare l'intercettore angolare per gestire le richieste di chiamate 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

Sto usando il servizio $http di angular per fare una richiesta Ajax.

Come mostrare un caricatore GIF durante la richiesta Ajax?

Non vedo alcun evento ajaxstartevent o simile nella documentazione.


Condivisione della mia versione della grande risposta da @bulltorious, aggiornata per le nuove versioni angolari (ho usato la versione 1.5.8 con questo codice) e incorporata anche l'idea di JMaylin di utilizzare un contatore in modo da essere efficace per più richieste simultanee e opzione per saltare la visualizzazione dell'animazione per le richieste che richiedono meno di un numero minimo di millisecondi:

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

Ecco la mia implementazione, semplice come un ng-show e un contatore di richieste.

Usa un nuovo servizio per tutte le richieste a $ 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--;
        });
    }
} ]);

E poi puoi usare la base del tuo caricatore sul numero di chiamate correnti:

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

Ecco la mia soluzione che sento è molto più facile che l'altro pubblicato qui. Non sono sicuro di quanto "carina" sia, ma ha risolto tutti i miei problemi

Ho uno stile css chiamato "caricamento"

.loading { display: none; }

L'html per il caricamento può essere qualunque, ma ho usato alcune icone FontAwesome e il metodo di rotazione lì:

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

Sugli elementi che vuoi nascondere semplicemente scrivi questo:

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

e nella funzione ho appena impostato questo carico.

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

Sto usando SignalR così nella funzione hubProxy.client.allLocks (quando ha finito i lock) I jut put

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

Questo nasconde anche il {{someField}} quando la pagina si sta caricando poiché sto impostando la classe di caricamento su load e AngularJS lo rimuove in seguito.


Il seguente metodo prenderà nota di tutte le richieste e si nasconderà solo una volta che tutte le richieste sono state fatte:

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


Per i caricamenti di pagina e le modali il modo più semplice è utilizzare la directory ng-show e utilizzare una delle variabili di dati dell'ambito. Qualcosa come ng-show = "angular.isUndefined (scope.data.someobject)". Poiché i dati non sono definiti, lo spinner mostrerà. Una volta che il servizio ritorna con i dati e l'ambito è popolato, lo spinner sarà nascosto.


Questo dipende molto dal tuo caso d'uso specifico, ma un modo semplice seguirebbe uno schema come questo:

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

E poi reagisci ad esso nel tuo modello:

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

Questo funziona bene per me:

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>

Angolare:

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

Mentre la promessa restituita da $ http è in sospeso, ng-show valuterà che sia "veritiera". Questo viene aggiornato automaticamente una volta risolta la promessa ... che è esattamente ciò che vogliamo.


Se si utilizza ngResource, l'attributo $ resolved di un oggetto è utile per i programmi di caricamento:

Per una risorsa come segue:

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

È possibile collegare un caricatore all'attributo $ resolved dell'oggetto risorsa:

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

Tutte le risposte sono o complicate, o hanno bisogno di impostare alcune variabili su ogni richiesta che è una pratica molto sbagliata se conosciamo il concetto DRY. Qui semplice esempio di intercettore, tengo il mouse in attesa quando ajax si avvia e lo imposta su auto quando termina l'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;
      }
    };
  });

Il codice deve essere aggiunto nell'applicazione config app.config . Ho mostrato come cambiare il mouse sullo stato di caricamento, ma in esso è possibile mostrare / nascondere qualsiasi contenuto del caricatore, o aggiungere, rimuovere alcune classi css che mostrano il loader.

Interceptor verrà eseguito su ogni chiamata Ajax , quindi non è necessario creare variabili booleane speciali ($ scope.loading = true / false ecc.) Su ogni chiamata http.


creare una direttiva con questo codice:

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

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

se vuoi mostrare loader per ogni chiamata di richiesta http allora puoi usare l'intercettore angolare per gestire le chiamate di richiesta http,

ecco un codice di esempio

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

Ecco gli incantesimi del passato 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']).
//.......

Ecco il resto (HTML / CSS) .... usando

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

per attivarlo. NOTA: quanto sopra è utilizzato nel modulo angolare all'inizio del post

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

Ecco una versione che utilizza una directive e ng-hide .

Questo mostrerà il loader durante tutte le chiamate tramite il servizio $http .

Nel modello:

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

direttiva:

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

usando la classe ng-hide sull'elemento, puoi evitare jquery.

Personalizza: aggiungi un interceptor

Se si crea un'intercettore di caricamento, è possibile mostrare / nascondere il caricatore in base a una condizione.

direttiva:

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

intercettore:

  • per esempio: non mostrare lo spinner quando response.background === true;
  • request intercettazione e / o response per impostare $rootScope.$broadcast("loader_show"); o $rootScope.$broadcast("loader_hide");

maggiori informazioni su come scrivere un intercettore


Usato in seguito all'intercettatore per mostrare la barra di caricamento su richiesta 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;
}]);

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




angularjs