Apply loading spinner during ui-router resolve

后端 未结 6 1213
面向向阳花
面向向阳花 2020-12-22 17:34

resolve property of $routeProvider allows to execute some jobs BEFORE corresponding view is rendered.

What if I want to display a spinner

相关标签:
6条回答
  • 2020-12-22 17:49

    I'm two years late to this, and yes these other solutions work but I find it easier to just handle all this in a just a run block like so

    .run(['$rootScope','$ionicLoading', function ($rootScope,$ionicLoading){
    
    
      $rootScope.$on('loading:show', function () {
        $ionicLoading.show({
            template:'Please wait..'
        })
      });
    
      $rootScope.$on('loading:hide', function () {
        $ionicLoading.hide();
      });
    
      $rootScope.$on('$stateChangeStart', function () {
        console.log('please wait...');
        $rootScope.$broadcast('loading:show');
      });
    
      $rootScope.$on('$stateChangeSuccess', function () {
        console.log('done');
        $rootScope.$broadcast('loading:hide');
      });
    
    }])
    

    You don't need anything else. Pretty easy huh. Here's an example of it in action.

    0 讨论(0)
  • 2020-12-22 17:56

    You can use a directive that listens on $routeChangeStart and for example shows the element when it fires:

    app.directive('showDuringResolve', function($rootScope) {
    
      return {
        link: function(scope, element) {
    
          element.addClass('ng-hide');
    
          var unregister = $rootScope.$on('$routeChangeStart', function() {
            element.removeClass('ng-hide');
          });
    
          scope.$on('$destroy', unregister);
        }
      };
    });
    

    Then you place it on the specific view's loader, for example:

    View 1:

    <div show-during-resolve class="alert alert-info">
      <strong>Loading.</strong>
      Please hold.
    </div>
    

    View 2:

    <span show-during-resolve class="glyphicon glyphicon-refresh"></span>
    

    The problem with this solution (and many other solutions for that matter) is that if you browse to one of the routes from an external site there will be no previous ng-view template loaded, so your page might just be blank during resolve.

    This can be solved by creating a directive that will act as a fallback-loader. It will listen for $routeChangeStart and show a loader only if there is no previous route.

    A basic example:

    app.directive('resolveLoader', function($rootScope, $timeout) {
    
      return {
        restrict: 'E',
        replace: true,
        template: '<div class="alert alert-success ng-hide"><strong>Welcome!</strong> Content is loading, please hold.</div>',
        link: function(scope, element) {
    
          $rootScope.$on('$routeChangeStart', function(event, currentRoute, previousRoute) {
            if (previousRoute) return;
    
            $timeout(function() {
              element.removeClass('ng-hide');
            });
          });
    
          $rootScope.$on('$routeChangeSuccess', function() {
            element.addClass('ng-hide');
          });
        }
      };
    });
    

    The fallback loader would be placed outside the element with ng-view:

    <body>
      <resolve-loader></resolve-loader>
      <div ng-view class="fadein"></div>
    </body>
    

    Demo of it all: http://plnkr.co/edit/7clxvUtuDBKfNmUJdbL3?p=preview

    0 讨论(0)
  • 2020-12-22 18:08

    In ui-router 1.0 $stateChange* events are deprecated. Use transition hook instead. See migration guide below for more details.

    https://ui-router.github.io/guide/ng1/migrate-to-1_0#state-change-events

    0 讨论(0)
  • 2020-12-22 18:08

    The problem with '$stateChangeStart' and '$stateChangeSuccess' is "$rootScope.stateIsLoading" doesn't get refreshed when you go back to last state. Is there any solution on that? I also used:

        $rootScope.$on('$viewContentLoading',
            function(event){....});
    

    and

        $rootScope.$on('$viewContentLoaded',
            function(event){....});
    

    but there is the same issue.

    0 讨论(0)
  • 2020-12-22 18:12

    To further Pranay's answer this is how I did it.

    JS:

    app.run(['$rootScope',function($rootScope){
    
        $rootScope.stateIsLoading = false;
        $rootScope.$on('$routeChangeStart', function() {
            $rootScope.stateIsLoading = true;
        });
        $rootScope.$on('$routeChangeSuccess', function() {
            $rootScope.stateIsLoading = false;
        });
        $rootScope.$on('$routeChangeError', function() {
            //catch error
        });
    
    }]);
    

    HTML

    <section ng-if="!stateIsLoading" ng-view></section>
    <section ng-if="stateIsLoading">Loading...</section>
    
    0 讨论(0)
  • 2020-12-22 18:15

    i think this is pretty neat

    app.run(['$rootScope', '$state',function($rootScope, $state){
    
      $rootScope.$on('$stateChangeStart',function(){
          $rootScope.stateIsLoading = true;
     });
    
    
      $rootScope.$on('$stateChangeSuccess',function(){
          $rootScope.stateIsLoading = false;
     });
    
    }]);
    

    and then on view

    <div ng-show='stateIsLoading'>
      <strong>Loading.</strong>
    </div>
    
    0 讨论(0)
提交回复
热议问题