(Angular -ui-router) Показывать анимацию загрузки во время процесса разрешения
Это вопрос из двух частей:
-
Я использую свойство разрешения внутри $stateProvider.state() для захвата определенных данных сервера перед загрузкой контроллера. Как я могу получить анимацию загрузки, отображаемую во время этого процесса?
-
У меня есть дочерние состояния, которые также используют свойство разрешения. Проблема в том, что ui-router, по-видимому, хочет завершить работу all до загрузки любого контроллера. Есть ли способ, с помощью которого родительские контроллеры могут загружаться после того, как их разрешения будут разрешены, не дожидаясь разрешения всех дочерних элементов? Ответ на это, скорее всего, также решит первую проблему.
Ответы
Ответ 1
EDIT: это еще более простое решение, хорошо протестированное и работающее:
В моем основном контроллере я просто
$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();
}
});
Это показывает счетчик, когда мы собираемся перейти в состояние, в котором есть что разрешить и скрыть его, когда изменение состояния завершено. Возможно, вы захотите добавить некоторую проверку иерархии состояний (т.е. Также показать spinner, если родительское состояние, которое загружается, разрешает что-то), но это решение отлично подходит для меня.
Вот мое старое предложение для справки и в качестве альтернативы:
-
В своем контроллере приложений прослушайте событие stateChangeStart
и проверьте, не собираетесь ли вы переключиться на состояние, в котором вы хотите отобразить счетчик во время разрешения (см. 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
}
})
-
Когда вы, наконец, вызываете контроллер, вы можете спрятать spinner
.controller('StateWithResolveCtrl', function($scope) {
$scope.hideSpinner();
})
Вы также можете проверить наличие ошибок, которые могли произойти во время разрешения, прослушивая событие $stateChangeError
и скрывая анимацию, когда вы обрабатываете ошибку.
Это не совсем чисто, поскольку вы распространяете логику для счетчика между контроллерами, но это способ. Надеюсь, что это поможет.
Ответ 2
Я разработал следующее решение, которое отлично работает для меня.
1. Добавьте следующий 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. Поместите индикатор загрузки чуть выше ui-view. Добавьте id = "ui-view" в ui-view div.
<div class="page-loading">Loading...</div>
<div ui-view id="ui-view"></div>
3. добавьте следующее к вашему css
.hidden {
display: none !important;
visibility: hidden !important;
}
Примечание:
а. В приведенном выше коде будет отображаться индикатор загрузки в двух случаях 1), когда приложение angular загружается впервые 2) при изменении представления.
В. Если вы не хотите, чтобы индикатор отображался, когда приложение angular загружается в первый раз (перед загрузкой любого вида), добавьте класс скрытый в загружаемый div, как показано ниже
<div class="page-loading hidden">Loading...</div>
Ответ 3
Я нашел, что angular-loading-bar работал очень хорошо для долгого разрешения из-за доступа к сети.
Ответ 4
Как добавить контент в div, который будет заполнен ui-router после разрешения свойств?
В index.html
<div ui-view class="container">
Loading....
</div>
Теперь пользователь увидит "Загрузка...", пока свойства будут разрешены. Когда все будет готово, контент будет заменен на ui-router содержимым ваших приложений.
Ответ 5
Я использую анимированный gif, который я показываю только тогда, когда $http
имеет ожидающие запросы.
В моем шаблоне базовой страницы у меня есть навигатор и навигатор. Соответствующая часть контроллера выглядит следующим образом:
controllers.controller('NavbarCtrl', ['$scope', '$http',
function ($scope, $http) {
$scope.hasPendingRequests = function () {
return $http.pendingRequests.length > 0;
};
}]);
Соответствующий код в моем html:
<span class="navbar-spinner" ng-show="hasPendingRequests()">
<img src="/static/img/spinner.gif">
</span>
Я надеюсь, что это поможет!
Ответ 6
Моя идея - пройти путь по графу состояний между переходными состояниями на $stateChangeStart
и собрать все задействованные представления. Затем каждая директива ui-view
наблюдает, если соответствующий переход участвует в переходе и добавляет к нему элемент 'ui-resolving'
.
В демонстрации plunker представлены два состояния корня: first
и second
, у последнего есть два подстава second.sub1
и second.sub2
, Состояние second.sub2
также нацелено на представление footer
, которое принадлежит его прародителю.
Ответ 7
Это загрузчик по всему миру, когда страница перемещается между любым состоянием (любая страница), помещается в 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;
})
}
])
В html:
<div ng-show="preloader">Loading...</div>
Ответ 8
Я предпочитаю использовать директиву для соответствия любой нагрузке, главным образом, чтобы моя кодовая основа была чистой
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);
}
}
}]);
Ответ 9
Моя идея использовать представление при использовании resole в маршрутизаторе работает потрясающе. попробуй это.
//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;
});
});
Ответ 10
Если кто-то использует ngRoute
, ожидая в resolve
перед загрузкой следующего представления и используя angular-bootstrap-ui
для ui, вы можете сделать следующее:
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;
}
]
}
});
}
]);