To jest dwuczęściowe pytanie:
Używam właściwości resolution wewnątrz $ stateProvider.state (), aby pobrać określone dane serwera przed załadowaniem kontrolera. Jak mam się postarać o wyświetlenie animacji ładowania podczas tego procesu?
Mam stany potomne, które również wykorzystują właściwość rozwiązania. Problem polega na tym, że router ui wydaje się chcieć sfinalizować wszystkie rozwiązania przed załadowaniem dowolnego kontrolera. Czy jest jakiś sposób, żebym mógł załadować kontrolery nadrzędne po rozwiązaniu ich decyzji, bez konieczności czekania na wszystkie rozwiązania dziecka? Odpowiedź na to prawdopodobnie rozwiąże również pierwszy problem.
javascript
angularjs
angular-ui-router
Matt Way
źródło
źródło
Odpowiedzi:
EDYCJA: Oto jeszcze łatwiejsze rozwiązanie, przetestowane i ładnie działające:
W moim głównym kontrolerze po prostu mam
$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(); } });
To pokazuje spinner za każdym razem, gdy zbliżamy się do stanu, który ma coś do rozwiązania i ukrywa to, gdy zmiana stanu jest zakończona. Możesz chcieć dodać kilka sprawdzeń w górę hierarchii stanów (tj. Pokazać także spinner, jeśli ładowany stan nadrzędny coś rozwiązuje), ale to rozwiązanie działa dobrze dla mnie.
Oto moja stara sugestia w celach informacyjnych i jako alternatywa:
W kontrolerze aplikacji posłuchaj
stateChangeStart
zdarzenia i sprawdź, czy masz zamiar przejść do stanu, w którym chcesz wyświetlać pokrętło podczas rozwiązywania (patrz https://github.com/angular-ui/ui-router/wiki/Quick -Reference # 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 } })
Kiedy kontroler w końcu zostanie wywołany, możesz ukryć pokrętło
.controller('StateWithResolveCtrl', function($scope) { $scope.hideSpinner(); })
Możesz również sprawdzić, czy nie wystąpiły błędy, które mogły wystąpić podczas rozwiązywania, nasłuchując pliku
$stateChangeError
zdarzenia i ukrywając animację podczas obsługi błędu.Nie jest to całkowicie czyste, ponieważ rozdzielasz logikę pokrętła między kontrolerami, ale jest to sposób. Mam nadzieję, że to pomoże.
źródło
if (toState.resolve)
sprawdza, czy konfiguracja stanu ma słownik rozwiązywania. W moim przypadku jest to wystarczająco dobre oszacowanie, że stan wykonuje wywołania usługi asynchronicznej. Zakładam, że jeśli istnieje blok rozstrzygania, to są rozwiązywane zgłoszenia serwisowe. Kod pokazuje i ukrywa spinner tylko wtedy, gdy wykonano wezwanie serwisu. Jak opisałem powyżej, ten kod może wymagać dopracowania, aby sprawdzał również stany nadrzędne, w zależności od przypadku użycia.$scope
w wywołaniu$rootScope
. skąd$scope
się tu wzięło?showSpinner
została zdefiniowana funkcja.toState.resolve
więc użyłemfromState.name !== toState.name
. Poza tym twoja odpowiedź jest fantastyczna, dobra robota!Opracowałem następujące rozwiązanie, które działa idealnie dla mnie.
1. Dodaj następujący plik app.run
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. Umieść wskaźnik ładowania tuż nad widokiem interfejsu użytkownika. Dodaj id = "ui-view" do div ui-view.
<div class="page-loading">Loading...</div> <div ui-view id="ui-view"></div>
3. Dodaj następujące elementy do swojego css
.hidden { display: none !important; visibility: hidden !important; }
UWAGA:
A. Powyższy kod wyświetli wskaźnik ładowania w dwóch przypadkach 1) przy pierwszym załadowaniu aplikacji kątowej 2) przy zmianie widoku.
B. Jeśli nie chcesz, aby wskaźnik był wyświetlany, gdy aplikacja kątowa ładuje się po raz pierwszy (przed załadowaniem jakiegokolwiek widoku), dodaj ukrytą klasę do elementu div ładowania, jak poniżej
<div class="page-loading hidden">Loading...</div>
źródło
run
kod nie jest więc Angular Way. Zamiast manipulować tam dom, zestaw zmiennych zakres, jakloadingVisible
iviewVisible
, a następnie w HTML, koniecznie powiedzieć, gdy elementy są widoczne lub ukryte, jak:<div class="page-loading" ng-show="viewVisible">Loading...</div>
. Aby opróżnić widok, może jednak wymagać niestandardowej dyrektywy.Zauważyłem, że używanie kątowego paska ładowania działa bardzo dobrze w przypadku długich problemów z powodu dostępu do sieci.
źródło
Co powiesz na dodanie treści do div, która zostanie wypełniona przez router ui, gdy właściwości zostaną rozwiązane?
W Twoim
index.html
<div ui-view class="container"> Loading.... </div>
Podczas rozwiązywania właściwości użytkownik zobaczy teraz komunikat „Ładowanie ...”. Gdy wszystko będzie gotowe, zawartość zostanie zastąpiona przez router ui z zawartością aplikacji.
źródło
Używam animowanego gifa, który pokazuję tylko wtedy, gdy
$http
ma oczekujące żądania.W moim szablonie strony bazowej mam pasek nawigacyjny i kontroler paska nawigacyjnego. Odpowiednia część kontrolera wygląda następująco:
controllers.controller('NavbarCtrl', ['$scope', '$http', function ($scope, $http) { $scope.hasPendingRequests = function () { return $http.pendingRequests.length > 0; }; }]);
Odpowiedni kod w moim html to:
<span class="navbar-spinner" ng-show="hasPendingRequests()"> <img src="/static/img/spinner.gif"> </span>
Mam nadzieję że to pomogło!
źródło
Moim pomysłem jest przejście ścieżką na wykresie stanu między przechodzącymi stanami
$stateChangeStart
i zebranie wszystkich zaangażowanych widoków. Następnie każdaui-view
dyrektywa obserwuje, czy odpowiedni widok jest zaangażowany w przejście i dodaje'ui-resolving'
klasę do swojego elementu.Plunker demo wprowadza dwa stany root:
first
asecond
ten ostatni ma dwie podstanamisecond.sub1
isecond.sub2
. Państwosecond.sub2
kieruje się również poglądamifooter
należącymi do jego dziadków.źródło
To jest ładowarka globalna, gdy nawigacja po stronie między dowolnym stanem (dowolna strona), umieszczona w 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; }) } ])
W html:
<div ng-show="preloader">Loading...</div>
źródło
Wolę używać dyrektywy, aby dopasować każdą czynność ładowania, głównie w celu utrzymania czystości mojej bazy kodu
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); } } }]);
źródło
Użycie
$stateChangeStart
i tym podobnych zostało od tego czasu przestarzałe i zastąpione przejściami . Tak więc, dla odpowiedzi Stefana Henze, zaktualizowana wersja będzie wyglądać tak:$transitions.onStart({}, function(transition) { if (transition.to().resolve) { $scope.showSpinner(); } }); $transitions.onSuccess({}, function(transition) { if (transition.to().resolve) { $scope.hideSpinner(); } });
Możesz użyć tego w swoim kontrolerze nadrzędnym. Pamiętaj o wstrzyknięciu
$transitions
-.controller('parentController',['$transitions',function($transitions){...}]);
Pamiętaj też,
resolve
że obiekt będący pustym obiektem będzie nadal renderowanytransition.to().resolve == true
, więc nie zostawiaj pustego symbolu zastępczegoresolve
w deklaracji stanu.źródło
Mój pomysł, aby użyć widoku podczas używania resole w routerze, działa niesamowicie. Spróbuj tego.
//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; }); });
źródło
Jeśli ktoś używa
ngRoute
, czeka naresolve
załadowanie następnego widoku i używaangular-bootstrap-ui
interfejsu użytkownika, możesz wykonać następujące czynności :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; } ] } }); } ]);
źródło