在解析过程中显示加载动画

这是一个由两部分组成的问题:

  1. 我正在使用 $stateProvider.state ()中的 decision 属性在加载控制器之前获取某些服务器数据。在这个过程中,我如何获得一个加载动画来显示?

  2. 我有子状态,也利用解析性质。问题是 ui 路由器似乎想在加载 任何控制器之前完成 所有解析。有没有什么方法可以让父控制器在解析完成后加载它们,而不必等待所有子控制器的解析?这个问题的答案可能也会解决第一个问题。

53057 次浏览

我使用一个动画的 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>

我希望这能有所帮助!

如何将内容添加到 div 中,一旦属性解析后,ui-router 将填充这些内容?

在你的 index.html

<div ui-view class="container">
Loading....
</div>

在解析属性时,用户现在将看到“ Loading...”。一旦一切准备就绪,内容将被 ui-router 替换为您的应用程序内容。

编辑: 这里有一个更简单的解决方案,经过测试,效果很好:

在我的主控制器中

$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) ,但是这个解决方案对我来说很好用。

以下是我的老建议,作为参考和替代:

  1. 在应用程序控制器中,侦听 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
    }
    })
    
  2. When you controller finally gets called, you can hide the spinner

    .controller('StateWithResolveCtrl', function($scope) {
    $scope.hideSpinner();
    })
    

You also might want to check for any errors that may have occurred during resolve by listening to the $stateChangeError event and hiding the animation while you handle the error.

This is not totally clean as you distribute the logic for the spinner between controllers, but it's a way. Hope it helps.

我开发了以下的解决方案,它完全适合我。

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;
}

注意:

A.上面的代码将显示加载指示器在两种情况下 1)时,角度应用程序是第一次加载 2)时,视图被改变。

B.如果您不希望在角度应用程序首次加载时(在加载任何视图之前)显示指示器,那么将 藏起来了类添加到加载 div 中,如下所示

<div class="page-loading hidden">Loading...</div>

我发现,由于网络访问,使用 角加载杆角加载杆可以很好地长时间解决问题。

我的想法是沿着状态图在 $stateChangeStart上的过渡状态之间行走,并收集所有相关的视图。然后每个 ui-view指令监视相应的视图是否参与转换,并在其元素上添加 'ui-resolving'类。

混蛋演示引入了两种根状态: firstsecond,后者有两个分站 second.sub1second.sub2。状态 second.sub2还针对属于其祖辈的 footer视图。

我更喜欢使用指令来匹配任何加载活动,主要是为了保持代码库的整洁

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);
}
}
}]);

如果有人正在使用 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;
}
]
}
});
}
]);

我的想法使用视图,而使用路由器中的分辨率,它是工作真棒。尝试这一点。

//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;
});


});

这是用于在任何状态(任何页面)之间进行页面导航时的全局加载程序,请输入 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>

使用 $stateChangeStart和类似的技术已经被废弃,取而代之的是 过渡挂钩。所以,对于 Stefan Henze 的回答,更新的版本是:

$transitions.onStart({}, function(transition) {
if (transition.to().resolve) {
$scope.showSpinner();
}
});


$transitions.onSuccess({}, function(transition) {
if (transition.to().resolve) {
$scope.hideSpinner();
}
});

您可以在父控制器中使用它

.controller('parentController',['$transitions',function($transitions){...}]);

另外,请记住,作为空对象的 resolve仍将呈现 transition.to().resolve == true,因此不要在状态声明中留下空占位符 resolve