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