简体   繁体   English

(Angular-ui-router)在解析过程中显示加载动画

[英](Angular-ui-router) Show loading animation during resolve process

This is a two part question: 这是一个两部分问题:

  1. I am using the resolve property inside $stateProvider.state() to grab certain server data before loading the controller. 我在$ stateProvider.state()中使用resolve属性来在加载控制器之前获取某些服务器数据。 How would I go about getting a loading animation to show during this process? 如何在此过程中显示加载动画?

  2. I have child states that also utilise the resolve property. 我有子状态也使用resolve属性。 The problem is that ui-router seems to want to finalise all resolves before loading any controller. 问题是ui-router似乎想要在加载任何控制器之前完成所有解析。 Is there any way I can get the parent controllers to load once their resolves have been resolved, without having to wait for all the child resolves? 有没有什么办法可以让他们在解析后解析父控制器,而不必等待所有的子解析? An answer to this will likely also solve the first problem. 对此的答案也可能解决第一个问题。

EDIT: Here is an even easier solution, tested and working nicely: 编辑:这是一个更简单的解决方案,测试和工作很好:

In my main controller I simply have 在我的主控制器中,我只是

$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();
    }
});

This shows the spinner whenever we are about to go to a state that has anything to resolve and hides it, when the state change is complete. 当状态更改完成时,无论何时我们要进入有任何需要解决的状态并隐藏它,都会显示微调器。 You might want to add some check up the state hierarchy (ie also show the spinner if a parent state that is being loaded resolves something) but this solution works fine for me. 您可能想要添加一些检查状态层次结构(即如果正在加载的父状态解析某些内容,也会显示微调器),但此解决方案对我来说很好。

Here is my old suggestion for reference and as an alternative: 这是我的旧建议供参考,作为替代方案:

  1. In your application controller, listen to the stateChangeStart event and check if you are about to switch to a state where you want to show a spinner during resolve (see https://github.com/angular-ui/ui-router/wiki/Quick-Reference#wiki-events-1 ) 在应用程序控制器中,监听stateChangeStart事件并检查是否要在解析期间切换到要显示微调器的状态(请参阅https://github.com/angular-ui/ui-router/wiki/快速参考#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. 您还可能希望通过侦听$stateChangeError事件并在处理错误时隐藏动画来检查解析期间可能发生的任何错误。

This is not totally clean as you distribute the logic for the spinner between controllers, but it's a way. 当你在控制器之间分配微调器的逻辑时,这并不完全干净,但这是一种方式。 Hope it helps. 希望能帮助到你。

I developed the following solution which works perfectly for me. 我开发了以下解决方案,它对我来说非常有效。

1. Add the following app.run 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. Place the loading indicator just above the ui-view. 2.将加载指示器放在ui视图的正上方。 Add id="ui-view" to ui-view div. 将id =“ui-view”添加到ui-view div。

<div class="page-loading">Loading...</div>
<div ui-view id="ui-view"></div>

3. add the following to your css 3.将以下内容添加到您的CSS中

.hidden {
  display: none !important;
  visibility: hidden !important;
}

NOTE: 注意:

A. The above code will display loading indicator in two cases 1) when the angular app is loaded first time 2) when the view is changed. A.以上代码将在两种情况下显示加载指示器1)当角度应用程序第一次加载时2)当视图更改时。

B. If you don't want the indicator to be shown when the angular app loads first time (before any view is loaded), then add hidden class to the loading div like below B.如果您不希望在角度应用第一次加载时(在加载任何视图之前)显示指标,则将隐藏的类添加到加载div中,如下所示

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

我发现由于网络访问,使用角度加载条非常适合长时间的解析。

How about adding content to the div that will be filled by ui-router once the properties have resolved? 如果属性已解决,如何将内容添加到将由ui-router填充的div中?

In your index.html 在你的index.html

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

The user will now see "Loading..." while the properties are resolved. 现在,用户将在解析属性时看到“正在加载...”。 Once everything is ready the content will be replace by ui-router with your apps content. 一切准备就绪后,内容将由ui-router替换为您的应用内容。

I use an animated gif that I show only when $http has pending requests. 我使用的动画gif仅在$http有未决请求时显示。

In my base page template, I have a navbar and navbar controller. 在我的基页模板中,我有一个导航栏和导航栏控制器。 The relevant part of the controller looks like this: 控制器的相关部分如下所示:

controllers.controller('NavbarCtrl', ['$scope', '$http',
    function ($scope, $http) {
        $scope.hasPendingRequests = function () {
            return $http.pendingRequests.length > 0;
        };
    }]);

The corresponding code in my html is: 我的html中的相应代码是:

<span class="navbar-spinner" ng-show="hasPendingRequests()">
    <img src="/static/img/spinner.gif">
</span>

I hope that helps! 我希望有所帮助!

My idea is to walk the path on state graph between transitioning states on $stateChangeStart and collect all involved views. 我的想法是在$stateChangeStart上的转换状态之间走状态图,并收集所有涉及的视图。 Then every ui-view directive watches if corresponding view is involved in transition and adds 'ui-resolving' class on it's element. 然后,每个ui-view指令都会ui-view转换中是否包含相应的视图,并在其元素上添加'ui-resolving'类。

The plunker demo introduces two root states: first and second , the latter has two substates second.sub1 and second.sub2 . plunker演示引入了两个根状态: firstsecond ,后者有两个子状态second.sub1second.sub2 The state second.sub2 also targets footer view that belongs to its grandparent. second.sub2也针对属于其祖父母的footer视图。

This is loader for globally when page navigate between any state (any page), put in app.js 当在任何状态(任何页面)之间进行页面导航时,这是全局加载器,放在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;
            })
        }
    ])

In html: 在html中:

<div ng-show="preloader">Loading...</div>

I prefer using a directive to match any loading activity, mainly to keep my codebase clean 我更喜欢使用指令来匹配任何加载活动,主要是为了保持我的代码库清洁

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

The use of $stateChangeStart and the like have since been deprecated and replaced with Transition Hooks . 之后不再使用$stateChangeStart等替换为Transition Hooks So, for the answer by Stefan Henze, the updated version would be: 因此,对于Stefan Henze的答案,更新版本将是:

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

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

You can use this in you parent controller. 您可以在父控制器中使用它。 Remember to inject $transitions - 记得注入$transitions -

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

Also, keep in mind that a resolve that is an empty object will still render transition.to().resolve == true , so don't leave an empty placeholder resolve in the state declaration. 另外,请记住,作为空对象的resolve仍将呈现transition.to().resolve == true ,因此不要在状态声明中留下空占位符resolve

My Idea to use view while using resole in router it is working awesome. 我的想法在路由器中使用resole时使用视图它工作真棒。 try this. 试试这个。

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

});

If anyone is using ngRoute , waiting on resolve before loading the next view, and using angular-bootstrap-ui for ui, you can do the following : 如果有人正在使用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;
          }
        ]
      }
    });
  }
]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM