C'est une question en deux parties:
J'utilise la propriété de résolution dans $ stateProvider.state () pour récupérer certaines données du serveur avant de charger le contrôleur. Comment pourrais-je obtenir une animation de chargement à afficher pendant ce processus?
J'ai des états enfants qui utilisent également la propriété resol. Le problème est que ui-router semble vouloir finaliser tout résout avant de charger tout contrôleur . Existe-t-il un moyen de charger les contrôleurs parents une fois leurs résolutions résolues, sans avoir à attendre que toutes les résolutions enfants soient résolues? Une réponse à cette question résoudra probablement également le premier problème.
EDIT: Voici une solution encore plus simple, testée et fonctionnant bien:
Dans mon contrôleur principal, j'ai simplement
$scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
if (toState.resolve) {
$scope.showSpinner();
}
});
$scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
if (toState.resolve) {
$scope.hideSpinner();
}
});
Cela montre le compteur lorsque nous sommes sur le point d’aller dans un état qui a quelque chose à résoudre et le cache, lorsque le changement d’état est terminé. Vous voudrez peut-être ajouter des éléments de contrôle dans la hiérarchie des états (c’est-à-dire aussi afficher le compteur si un état parent en cours de chargement résout quelque chose), mais cette solution me convient parfaitement.
Voici mon ancienne suggestion pour référence et comme alternative:
Dans votre contrôleur d’application, écoutez l’événement stateChangeStart
et vérifiez si vous êtes sur le point de passer à un état dans lequel vous souhaitez afficher un compteur pendant la résolution (voir https://github.com/angular -ui/routeur-ui/wiki/référence rapide # wiki-events-1 )
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
if (toState.name == 'state.with.resolve') {
$scope.showSpinner(); //this is a function you created to show the loading animation
}
})
Lorsque votre contrôleur est finalement appelé, vous pouvez masquer le compteur.
.controller('StateWithResolveCtrl', function($scope) {
$scope.hideSpinner();
})
Vous pouvez également vérifier les erreurs éventuelles lors de la résolution en écoutant le fichier $stateChangeError
événement et masquer l'animation pendant que vous gérez l'erreur.
Ce n'est pas tout à fait propre car vous distribuez la logique pour le spinner entre les contrôleurs, mais c'est un moyen. J'espère que ça aide.
J'ai développé la solution suivante qui fonctionne parfaitement pour moi.
1. Ajoutez l'app.run suivant
app.run(function($rootScope){
$rootScope
.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
$("#ui-view").html("");
$(".page-loading").removeClass("hidden");
});
$rootScope
.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){
$(".page-loading").addClass("hidden");
});
});
2. Placez l'indicateur de chargement juste au-dessus de la vue ui. Ajoutez id = "ui-view" au div. Ui-view.
<div class="page-loading">Loading...</div>
<div ui-view id="ui-view"></div>
. Ajoutez ce qui suit à votre css
.hidden {
display: none !important;
visibility: hidden !important;
}
NOTE:
A. Le code ci-dessus affichera l'indicateur de chargement dans deux cas 1) lorsque angular est chargée pour la première fois 2) lorsque la vue est changé.
B. Si vous ne voulez pas que l'indicateur soit affiché lorsque l'application angular est chargée pour la première fois (avant qu'une vue ne soit chargée), ajoutez alors hidden class à la chargement div comme ci-dessous
<div class="page-loading hidden">Loading...</div>
J'ai trouvé en utilisant angular-loading-bar qui fonctionnait très bien pendant de longues résolutions en raison de l'accès au réseau.
Pourquoi ne pas ajouter du contenu à la div qui sera rempli par ui-router une fois les propriétés résolues?
Dans votre index.html
<div ui-view class="container">
Loading....
</div>
L'utilisateur verra maintenant "Loading ..." pendant que les propriétés sont résolues. Une fois que tout est prêt, le contenu sera remplacé par ui-router par le contenu de vos applications.
J'utilise un gif animé que je montre uniquement quand $http
a des demandes en attente.
Dans mon modèle de page de base, j'ai une barre de navigation et un contrôleur de barre de navigation. La partie pertinente du contrôleur ressemble à ceci:
controllers.controller('NavbarCtrl', ['$scope', '$http',
function ($scope, $http) {
$scope.hasPendingRequests = function () {
return $http.pendingRequests.length > 0;
};
}]);
Le code correspondant dans mon HTML est:
<span class="navbar-spinner" ng-show="hasPendingRequests()">
<img src="/static/img/spinner.gif">
</span>
J'espère que ça aide!
Mon idée est de parcourir le graphe d’états entre états de transition sur $stateChangeStart
et rassemblez toutes les vues impliquées. Puis chaque ui-view
La directive surveille si la vue correspondante est impliquée dans la transition et ajoute 'ui-resolving'
classe sur son élément.
La démo plunker introduit deux états racine: first
et second
, ce dernier a deux sous-états second.sub1
et second.sub2
. L'état second.sub2
cible également footer
la vue appartenant à son grand-parent.
Ceci est un chargeur pour globalement quand la page navigue entre n'importe quel état (n'importe quelle page), mettez dans app.js
.run(
['$rootScope',
function($rootScope) {
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
$rootScope.preloader = true;
})
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
$rootScope.preloader = false;
})
}
])
En html:
<div ng-show="preloader">Loading...</div>
Je préfère utiliser une directive pour correspondre à toute activité de chargement, principalement pour garder ma base de code propre
angular.module('$utilityElements', [])
.directive('loader',['$timeout','$rootScope', function($timeout, $rootScope) {
return {
restrict: 'A',
template: '<div id="oneloader" class="hiddenload">loading...</div>',
replace: true,
compile: function (scope, element, attrs) {
$timeout(function(){
$rootScope
.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
$("#oneloader").removeClass("hiddenload");
});
$rootScope
.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){
//add a little delay
$timeout(function(){
$("#oneloader").addClass("hiddenload");
},500)
});
}, 0);
}
}
}]);
L'utilisation de $stateChangeStart
Et des éléments similaires a depuis été déconseillée et remplacée par Transition Hooks . Donc, pour la réponse de Stefan Henze, la version mise à jour serait:
$transitions.onStart({}, function(transition) {
if (transition.to().resolve) {
$scope.showSpinner();
}
});
$transitions.onSuccess({}, function(transition) {
if (transition.to().resolve) {
$scope.hideSpinner();
}
});
Vous pouvez l'utiliser dans votre contrôleur parent. N'oubliez pas d'injecter $transitions
-
.controller('parentController',['$transitions',function($transitions){...}]);
Aussi, gardez à l'esprit qu'un resolve
qui est un objet vide restituera toujours transition.to().resolve == true
, donc ne laissez pas d'espace réservé vide resolve
dans la déclaration d'état.
Mon idée d'utiliser la vue en utilisant la résolution dans le routeur ça marche génial. essaye ça.
//edit index.html file
<ion-nav-view>
<div ng-show="loadder" class="loddingSvg">
<div class="svgImage"></div>
</div>
</ion-nav-view>
// css file
.loddingSvg {
height: 100%;
background-color: rgba(0, 0, 0, 0.1);
position: absolute;
z-index: 99;
left: 0;
right: 0;
}
.svgImage {
background: url(../img/default.svg) no-repeat;
position: relative;
z-index: 99;
height: 65px;
width: 65px;
background-size: 56px;
top: 50%;
margin: 0 auto;
}
// edit app.js
.run(function($ionicPush, $rootScope, $ionicPlatform) {
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams) {
$rootScope.loadder = true;
});
$rootScope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams) {
$rootScope.loadder = false;
});
});
Si quelqu'un utilise ngRoute
, il faut attendre resolve
avant de charger la vue suivante et utiliser angular-bootstrap-ui
pour ui, vous pouvez faire le suivant :
app.config([
"$routeProvider", "$locationProvider", function($routeProvider, $locationProvider) {
return $routeProvider.when("/seasons/:seasonId", {
templateUrl: "season-manage.html",
controller: "SeasonManageController",
resolve: {
season: [
"$route", "$q", "$http", "$modal", function($route, $q, $http, $modal) {
var modal, promise, seasonId;
modal = $modal.open({
backdrop: "static",
template: "<div>\n <div class=\"modal-header\">\n <h3 class=\"modal-title\">\n Loading...\n </h3>\n </div>\n <div class=\"modal-body\">\n <progressbar\n class=\"progress-striped active\"\n value=\"'100'\">\n </progressbar>\n </div>\n</div>",
keyboard: false,
size: "lg"
});
promise = $q.defer();
seasonId = $route.current.params.seasonId;
$http.get("/api/match/seasons/" + seasonId).success(function(data) {
modal.close();
promise.resolve(data);
}).error(function(data) {
modal.close();
promise.reject(data);
});
return promise.promise;
}
]
}
});
}
]);