En utilisant Angularjs, j'ai besoin de montrer un écran de chargement (un simple spinner) jusqu'à ce que la requête ajax soit complète. Veuillez me suggérer une idée avec un extrait de code.
Réponses
Trop de publicités?Au lieu de configurer une variable de portée pour indiquer l'état de chargement des données, il est préférable qu'une directive fasse tout à votre place :
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();
}
});
}
};
}]);
Avec cette directive, il vous suffit de donner à tout élément d'animation de chargement un attribut "loading" :
<div class="loading-spiner-holder" data-loading ><div class="loading-spiner"><img src="..." /></div></div>
Vous pouvez avoir plusieurs spinners de chargement sur la page. L'endroit et la manière de disposer ces spinners dépendent de vous et directive les activera/désactivera automatiquement pour vous.
Voici un exemple. Il utilise la méthode simple ng-show avec un bool.
HTML
<div ng-show="loading" class="loading"><img src="...">LOADING...</div>
<div ng-repeat="car in cars">
<li>{{car.name}}</li>
</div>
<button ng-click="clickMe()" class="btn btn-primary">CLICK ME</button>
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 ce cas :
HTML :
<loading></loading>
DIRECTIVE ANGULARJS :
.directive('loading', function () {
return {
restrict: 'E',
replace:true,
template: '<div class="loading"><img src="..."/>LOADING...</div>',
link: function (scope, element, attr) {
scope.$watch('loading', function (val) {
if (val)
$(element).show();
else
$(element).hide();
});
}
}
})
J'utilise ngProgress pour ça.
Ajoutez 'ngProgress' à vos dépendances une fois que vous avez inclus les fichiers script/css dans votre HTML. Une fois que vous faites cela, vous pouvez mettre en place quelque chose comme ceci, 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();
});
};
N'oubliez pas d'ajouter 'ngProgress' aux dépendances des contrôleurs avant de le faire. Et si vous effectuez plusieurs requêtes AJAX, utilisez une variable incrémentale dans la portée de l'application principale pour savoir quand vos requêtes AJAX sont terminées avant d'appeler 'ngProgress.complete();'.
L'utilisation de pendingRequests n'est pas correcte car, comme indiqué dans la documentation d'Angular, cette propriété est principalement destinée à être utilisée à des fins de débogage.
Ce que je recommande est d'utiliser un intercepteur pour savoir s'il y a un appel asynchrone 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;
}
};
});
}]);
et ensuite vérifier si activeCalls est égal à zéro ou non dans la directive par le biais d'un $watch.
module.directive('loadingSpinner', function ($http) {
return {
restrict: 'A',
replace: true,
template: '<div class="loader unixloader" data-initialize="loader" data-delay="500"></div>',
link: function (scope, element, attrs) {
scope.$watch('activeCalls', function (newVal, oldVal) {
if (newVal == 0) {
$(element).hide();
}
else {
$(element).show();
}
});
}
};
});
La meilleure façon de procéder est d'utiliser intercepteurs de réponse ainsi que des directive . Et le processus peut encore être amélioré en utilisant pub/sub mécanisme utilisant $rootScope.$broadcast & $rootScope.$on méthodes.
Comme l'ensemble du processus est documenté dans un document bien rédigé article de blog Je ne vais pas le répéter ici. Veuillez vous référer à cet article pour mettre en place l'implémentation dont vous avez besoin.
- Réponses précédentes
- Plus de réponses