Dies ist eine zweiteilige Frage:
Ich verwende die Auflösungseigenschaft in $ stateProvider.state (), um bestimmte Serverdaten abzurufen, bevor der Controller geladen wird. Wie würde ich vorgehen, um eine Ladeanimation während dieses Vorgangs anzuzeigen?
Ich habe untergeordnete Zustände, die auch die Auflösungseigenschaft verwenden. Das Problem ist, dass der UI-Router anscheinend alle Auflösungen abschließen möchte, bevor ein Controller geladen wird. Gibt es eine Möglichkeit, die übergeordneten Controller zum Laden zu bringen, sobald ihre Auflösungen aufgelöst wurden, ohne auf alle untergeordneten Auflösungen warten zu müssen? Eine Antwort darauf wird wahrscheinlich auch das erste Problem lösen.
javascript
angularjs
angular-ui-router
Matt Way
quelle
quelle
Antworten:
EDIT: Hier ist eine noch einfachere Lösung, getestet und funktioniert gut:
In meinem Hauptcontroller habe ich einfach
$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(); } });
Dies zeigt den Spinner, wann immer wir in einen Zustand gehen, der etwas zu lösen hat, und verbirgt ihn, wenn die Zustandsänderung abgeschlossen ist. Möglicherweise möchten Sie die Statushierarchie überprüfen (dh auch den Spinner anzeigen, wenn ein überladener übergeordneter Status etwas auflöst), aber diese Lösung funktioniert für mich einwandfrei.
Hier ist mein alter Vorschlag als Referenz und als Alternative:
Hören
stateChangeStart
Sie sich in Ihrem Anwendungscontroller das Ereignis an und prüfen Sie, ob Sie während der Auflösung in einen Zustand wechseln möchten, in dem Sie einen Spinner anzeigen möchten (siehe https://github.com/angular-ui/ui-router/wiki/Quick) -Referenz # 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 } })
Wenn Ihr Controller endlich aufgerufen wird, können Sie den Spinner ausblenden
.controller('StateWithResolveCtrl', function($scope) { $scope.hideSpinner(); })
Möglicherweise möchten Sie auch nach Fehlern suchen, die während der Lösung aufgetreten sind, indem Sie das
$stateChangeError
Ereignis abhören und die Animation ausblenden, während Sie den Fehler behandeln.Dies ist nicht ganz sauber, da Sie die Logik für den Spinner auf die Controller verteilen, aber es ist ein Weg. Ich hoffe es hilft.
quelle
if (toState.resolve)
Überprüft, ob die Statuskonfiguration ein Auflösungswörterbuch enthält. In meinem Fall ist dies eine ausreichend gute Schätzung, dass der Status asynchrone Dienstaufrufe ausführt. Ich gehe davon aus, dass bei einem Auflösungsblock Serviceaufrufe aufgelöst werden. Der Code zeigt und versteckt den Spinner nur, wenn Serviceanrufe getätigt wurden. Wie oben beschrieben, muss dieser Code je nach Anwendungsfall möglicherweise verfeinert werden, um auch die übergeordneten Status zu überprüfen.$scope
in einem anruf auf$rootScope
. wo kommt das$scope
von hier hershowSpinner
Funktion definiert.toState.resolve
also habe ich es benutztfromState.name !== toState.name
. Abgesehen davon ist Ihre Antwort fantastisch, gut gemacht!Ich habe die folgende Lösung entwickelt, die perfekt für mich funktioniert.
1. Fügen Sie die folgende app.run hinzu
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. Platzieren Sie die Ladeanzeige direkt über der UI-Ansicht. Fügen Sie id = "ui-view" zu ui-view div hinzu.
<div class="page-loading">Loading...</div> <div ui-view id="ui-view"></div>
3. Fügen Sie Ihrem CSS Folgendes hinzu
.hidden { display: none !important; visibility: hidden !important; }
HINWEIS:
A. Der obige Code zeigt in zwei Fällen eine Ladeanzeige an: 1) wenn die Winkel-App zum ersten Mal geladen wird 2) wenn die Ansicht geändert wird.
B. Wenn Sie nicht möchten, dass der Indikator beim ersten Laden der Winkel-App angezeigt wird (bevor eine Ansicht geladen wird), fügen Sie dem Ladediv wie unten eine versteckte Klasse hinzu
<div class="page-loading hidden">Loading...</div>
quelle
run
Code ist soo nicht der Angular Way. Anstatt das DOM dort zu manipulieren, setzen Sie Bereichsvariablen wieloadingVisible
undviewVisible
und dann im HTML-Code unbedingt, wann die Elemente sichtbar oder ausgeblendet sind, wie :<div class="page-loading" ng-show="viewVisible">Loading...</div>
. Zum Leeren der Ansicht ist jedoch möglicherweise eine benutzerdefinierte Anweisung erforderlich.Ich habe festgestellt, dass die Verwendung der Winkelladestange aufgrund des Netzwerkzugriffs für lange Auflösungen sehr gut funktioniert.
quelle
Wie wäre es mit dem Hinzufügen von Inhalten zum div, die vom UI-Router ausgefüllt werden, sobald die Eigenschaften aufgelöst sind?
In deiner
index.html
<div ui-view class="container"> Loading.... </div>
Der Benutzer sieht nun "Laden ...", während die Eigenschaften aufgelöst werden. Sobald alles fertig ist, wird der Inhalt durch den UI-Router durch den Inhalt Ihrer Apps ersetzt.
quelle
Ich verwende ein animiertes GIF, das nur angezeigt wird, wenn
$http
ausstehende Anforderungen vorliegen.In meiner Basisseitenvorlage habe ich eine Navigationsleiste und einen Navigationsleisten-Controller. Der relevante Teil des Controllers sieht folgendermaßen aus:
controllers.controller('NavbarCtrl', ['$scope', '$http', function ($scope, $http) { $scope.hasPendingRequests = function () { return $http.pendingRequests.length > 0; }; }]);
Der entsprechende Code in meinem HTML lautet:
<span class="navbar-spinner" ng-show="hasPendingRequests()"> <img src="/static/img/spinner.gif"> </span>
Ich hoffe das hilft!
quelle
Meine Idee ist es, den Pfad im Zustandsdiagramm zwischen Übergangszuständen zu gehen
$stateChangeStart
und alle beteiligten Ansichten zu sammeln. Dannui-view
überprüft jede Direktive, ob die entsprechende Ansicht am Übergang beteiligt ist, und fügt'ui-resolving'
ihrem Element eine Klasse hinzu .Die Plunker- Demo führt zwei Root-Zustände ein:
first
undsecond
letzterer hat zwei Unterzuständesecond.sub1
undsecond.sub2
. Der Staatsecond.sub2
zielt auch auffooter
Ansichten ab, die seinen Großeltern gehören.quelle
Dies ist ein Loader für global, wenn die Seite zwischen einem beliebigen Status (einer beliebigen Seite) in app.js navigiert
.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; }) } ])
In HTML:
<div ng-show="preloader">Loading...</div>
quelle
Ich bevorzuge die Verwendung einer Direktive, um alle Ladeaktivitäten abzugleichen, hauptsächlich, um meine Codebasis sauber zu halten
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); } } }]);
quelle
Die Verwendung von
$stateChangeStart
und dergleichen wurde inzwischen veraltet und durch Übergangshaken ersetzt . Für die Antwort von Stefan Henze wäre die aktualisierte Version also:$transitions.onStart({}, function(transition) { if (transition.to().resolve) { $scope.showSpinner(); } }); $transitions.onSuccess({}, function(transition) { if (transition.to().resolve) { $scope.hideSpinner(); } });
Sie können dies in Ihrem übergeordneten Controller verwenden. Denken Sie daran zu injizieren
$transitions
-.controller('parentController',['$transitions',function($transitions){...}]);
Beachten Sie außerdem,
resolve
dass ein leeres Objekt weiterhin gerenderttransition.to().resolve == true
wird. Lassen Sie also keinen leeren Platzhalterresolve
in der Statusdeklaration.quelle
Meine Idee, die Ansicht zu verwenden, während Resole im Router verwendet wird, funktioniert hervorragend. Versuche dies.
//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; }); });
quelle
Wenn jemand verwendet
ngRoute
, wartet,resolve
bevor er die nächste Ansicht lädt, undangular-bootstrap-ui
für ui verwendet, können Sie Folgendes tun :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; } ] } }); } ]);
quelle