Angularjs écran de chargement sur demande ajax

En utilisant Angularjs, je dois afficher un écran de chargement (un simple spinner) jusqu’à ce que la requête ajax soit terminée. Veuillez suggérer une idée avec un extrait de code.

Au lieu de définir une variable de scope pour indiquer l’état de chargement des données, il est préférable qu’une directive fasse tout pour vous:

 angular.module('directive.loading', []) .directive('loading', ['$http' ,function ($http) { return { ressortingct: '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(); } }); } }; }]); 

Avec cette directive, il vous suffit de donner à un élément d’animation de chargement un atsortingbut “loading”:

 

Vous pouvez avoir plusieurs spinners de chargement sur la page. C’est à vous de décider où et comment mettre en forme ces fileurs et la directive va simplement l’activer / la désactiver automatiquement.

Voici un exemple. Il utilise la méthode simple ng-show avec un 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; }); } 

    Bien sûr, vous pouvez déplacer le code HTML de la boîte de chargement dans une directive, puis utiliser $ watch sur $ scope.loading. Dans quel cas:

    HTML :

      

    DIRECTIVE ANGULARJS :

      .directive('loading', function () { return { ressortingct: '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

    J’utilise ngProgress pour cela.

    Ajoutez ‘ngProgress’ à vos dépendances une fois que vous avez inclus les fichiers script / css dans votre code HTML. Une fois que vous faites cela, vous pouvez configurer quelque chose comme ça, qui se déclenchera lorsqu’un changement de route a été détecté.

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

    Pour les demandes AJAX, vous pouvez faire quelque chose comme ceci:

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

    Rappelez-vous juste d’append “ngProgress” aux dépendances des contrôleurs avant de le faire. Et si vous effectuez plusieurs requêtes AJAX, utilisez une variable incrémentielle dans la scope de l’application principale pour garder une trace de la fin des requêtes AJAX avant d’appeler ‘ngProgress.complete ();’.

    L’utilisation de pendingRequests n’est pas correcte car, comme mentionné dans la documentation angular, cette propriété est principalement destinée à être utilisée à des fins de débogage.

    Ce que je recommande, c’est d’utiliser un intercepteur pour savoir s’il y a un appel Async actif.

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

    puis vérifiez si activeCalls est égal à zéro ou non dans la directive via $ watch.

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

    La meilleure façon de faire est d’utiliser des intercepteurs de réponse avec une directive personnalisée. Et le processus peut encore être amélioré en utilisant le mécanisme pub / sub en utilisant $ rootScope. $ Broadcast & $ rootScope. $ Sur les méthodes.

    Comme tout le processus est documenté dans un article de blog bien écrit, je ne vais pas le répéter ici. S’il vous plaît se référer à cet article pour trouver votre implémentation nécessaire.

    En référence à cette réponse

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

    Pour moi, c’est la meilleure solution mais il y a un moyen d’éviter d’utiliser jQuery.

     .directive('loading', function () { return { ressortingct: '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}}
  • Mise en page typographique et angular

    directif

     ((): void=> { "use ssortingct"; angular.module("app").directive("busyindicator", busyIndicator); function busyIndicator($http:ng.IHttpService): ng.IDirective { var directive = { ressortingct: "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; } })(); 

    Portée

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

    Modèle

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

    Il y a aussi une belle démonstration qui montre comment utiliser l’animation Angularjs dans votre projet.
    le lien est ici
    http://yearofmoo-articles.github.io/angularjs-animation-article/app/#/ng-repeat (Voir le coin supérieur gauche) .
    C’est une source ouverte. voici le lien à télécharger
    https://github.com/yearofmoo-articles/AngularJS-Animation-Article
    Et voici le lien pour le tutoriel;
    http://www.yearofmoo.com/2013/04/animation-in-angularjs.html
    Mon point est, allez-y et téléchargez les fichiers source et ensuite voir comment ils ont implémenté le spinner. Ils ont peut-être utilisé un peu mieux l’approche. Alors, consultez ce projet.

    Si vous utilisez Restangular (ce qui est génial), vous pouvez créer une animation lors des appels api. Voici ma solution Ajouter un intercepteur de réponse et un intercepteur de requête qui envoie une diffusion rootscope. Ensuite, créez une directive pour écouter cette réponse et cette demande .:

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

    Voici la directive:

      angular.module('mean.system') .directive('smartLoadingIndicator', function($rootScope) { return { ressortingct: '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; }); } }; }) ;

    Incluez ceci dans votre “app.config”:

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

    Et ajoutez ce code:

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

    Utilisez angular-busy :

    Ajoutez cgBusy à votre application / module:

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

    Ajoutez votre promesse à la 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(); } 

    Dans votre template html:

     

    Voici un exemple simple d’intercepteur, je mets la souris en attente lorsque ajax démarre et la règle sur auto quand ajax se termine.

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

    Le code doit être ajouté dans l’application config app.config . J’ai montré comment changer la souris lors du chargement, mais il est possible d’afficher ou de masquer le contenu du chargeur, ou d’append, de supprimer certaines classes CSS qui affichent le chargeur.

    Interceptor s’exécutera à chaque appel ajax, donc pas besoin de créer des variables booléennes spéciales ($ scope.loading = true / false etc.) sur chaque appel http.

    L’intercepteur utilise un jqLite angular https://docs.angularjs.org/api/ng/function/angular.element construit, donc aucun Jquery n’est requirejs.

    Créez une directive avec les atsortingbuts show et size (vous pouvez en append d’autres)

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

    et en HTML utiliser comme

       

    Dans la variable show , passez true quand une promesse est en cours d’exécution et rendez cette valeur fausse lorsque la requête est terminée. Démo active – Exemple de démonstration de la directive Angular Loader dans JsFiddle

    J’ai construit un peu sur la réponse de @ DavidLin pour la simplifier – en supprimant toute dépendance à jQuery dans la directive. Je peux confirmer que cela fonctionne comme je l’utilise dans une application de production

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

    J’utilise un ng-show au lieu d’un appel jQuery pour masquer / afficher le

    .

    Voici le

    que j’ai placé juste en dessous de la ouverture:

     

    Et voici le CSS qui fournit la superposition pour bloquer l’interface utilisateur pendant qu’un appel $ http est en cours:

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

    Le crédit CSS va à @Steve Seeger’s – son article: https://stackoverflow.com/a/35470281/335545

    Vous pouvez append une condition, puis la modifier via le rootscope. Avant votre requête ajax, vous appelez simplement $ rootScope. $ Emit (‘stopLoader’);

     angular.module('directive.loading', []) .directive('loading', ['$http', '$rootScope',function ($http, $rootScope) { return { ressortingct: '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(); } }); } }; }]); 

    Ce n’est certainement pas la meilleure solution mais cela fonctionnerait toujours.