这是一个两部分的问题:
我在加载控制器之前使用$ stateProvider.state()中的resolve属性来获取某些服务器数据。如何在此过程中显示加载动画?
我有一些子状态也利用了resolve属性。问题是ui-router似乎要在加载任何控制器之前完成所有解析。有什么方法可以让父控制器在解析解决后加载,而不必等待所有子解析都加载?对此的答案可能也将解决第一个问题。
这是一个两部分的问题:
我在加载控制器之前使用$ stateProvider.state()中的resolve属性来获取某些服务器数据。如何在此过程中显示加载动画?
我有一些子状态也利用了resolve属性。问题是ui-router似乎要在加载任何控制器之前完成所有解析。有什么方法可以让父控制器在解析解决后加载,而不必等待所有子解析都加载?对此的答案可能也将解决第一个问题。
Answers:
编辑:这是一个甚至更简单的解决方案,经过测试并且运行良好:
在我的主控制器中,我只是
$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();
}
});
当状态更改完成时,只要我们要进入有任何要解决的状态并将其隐藏的状态,这就会显示微调框。您可能需要添加一些检查状态层次结构的方法(例如,如果正在加载的父状态可以解决问题,还可以显示微调器),但是这种解决方案对我来说效果很好。
这是我的旧建议,仅供参考:
在您的应用程序控制器中,侦听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
}
})
当控制器最终被调用时,您可以隐藏微调器
.controller('StateWithResolveCtrl', function($scope) {
$scope.hideSpinner();
})
您可能还希望通过$stateChangeError
在处理错误时侦听事件并隐藏动画来检查在解析过程中可能发生的任何错误。
当您在控制器之间分配微调器的逻辑时,这并不完全干净,但这是一种方法。希望能帮助到你。
if (toState.resolve)
检查状态配置是否具有解析字典。就我而言,这足以估计该状态是否进行了异步服务调用。我假设如果有一个resolve块,则是服务调用得到解决。该代码仅在进行服务调用时显示和隐藏微调框。如上所述,根据您的用例,可能需要改进此代码以检查父状态。
$scope
在上引用了$rootScope
。哪里的$scope
从这里来?
showSpinner
定义函数的地方。
toState.resolve
所以我用了fromState.name !== toState.name
。除此之外,您的答案很棒,做得很好!
我开发了以下最适合我的解决方案。
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视图上方。将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;
}
注意:
A.上面的代码将在两种情况下显示加载指示器:1)首次加载有角度的应用程序时2)更改视图时。
B.如果您不希望在有角度的应用程序首次加载时(在加载任何视图之前)显示该指示器,则将隐藏类添加到加载div中,如下所示
<div class="page-loading hidden">Loading...</div>
run
代码不是Angular Way。不用在那儿操纵DOM,而是设置范围变量,例如loadingVisible
和viewVisible
,然后在HTML中,强制性地说出元素何时可见或隐藏,例如:<div class="page-loading" ng-show="viewVisible">Loading...</div>
。为了清空视图,它可能需要一个自定义指令。
由于网络访问,我发现使用角度加载栏确实可以长期解决问题。
属性解析后,如何将内容添加到ui-router将填充的div中?
在你的 index.html
<div ui-view class="container">
Loading....
</div>
解析属性后,用户现在将看到“正在加载...”。一旦一切准备就绪,内容将被ui-router替换为您的应用程序内容。
我使用动画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>
希望对您有所帮助!
当页面在任何状态(任何页面)之间导航时,这是全局加载程序,放在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>
我更喜欢使用指令来匹配任何加载活动,主要是为了保持我的代码库干净
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);
}
}
}]);
采用$stateChangeStart
等所具有的,因为被弃用,取而代之的 过渡钩。因此,对于Stefan Henze的答案,更新版本为:
$transitions.onStart({}, function(transition) {
if (transition.to().resolve) {
$scope.showSpinner();
}
});
$transitions.onSuccess({}, function(transition) {
if (transition.to().resolve) {
$scope.hideSpinner();
}
});
您可以在父控制器中使用它。记得要注入$transitions
-
.controller('parentController',['$transitions',function($transitions){...}]);
另外,请记住,resolve
仍为空对象的a仍将呈现transition.to().resolve == true
,因此不要resolve
在状态声明中保留空的占位符。
我的想法是在路由器中使用鞋垫时使用视图,效果非常好。试试这个。
//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;
});
});
如果有人在使用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;
}
]
}
});
}
]);