Подтвердить что ты не робот

Примените загрузчик с помощью функции ui-router

resolve Свойство $routeProvider позволяет выполнять некоторые задания перед отображением соответствующего представления.

Что делать, если я хочу отображать счетчик, пока эти задания выполняются, чтобы увеличить пользовательский интерфейс?
В самом деле, в противном случае пользователь почувствовал бы, что приложение заблокировано, так как в течение нескольких миллисекунд > 600 не отображались элементы представления.

Конечно, был способ определить глобальный элемент div из текущего представления для отображения, чтобы отобразить счетчик благодаря функции $scope.$rootChangeStart.
Но я не хочу скрывать всю страницу с плохим поворотником посередине.
Я хочу, чтобы некоторые страницы моего веб-браузера отличались относительно способа отображения загрузки.

Я наткнулся на этот интересный пост, содержащий точный номер, который я описал выше:

Этот подход приводит к ужасному опыту пользовательского интерфейса. Пользователь нажимает кнопку, чтобы обновить список или что-то еще, и весь экран получает заполненном в родовом счетчике, потому что библиотека не имеет способа показывающий прядильщик только для вида (ов), на которые действительно влияет изменение состояния. Нет благодарности.

В любом случае, после того, как я подал эту проблему, я понял, что "решение" функция - анти-шаблон. Он ожидает, что все promises будут разрешены затем оживляет изменение состояния. Это совершенно неправильно - вы хотите ваши анимации перехода между состояниями для параллельной работы с вашими данными нагрузок, так что последний может быть закрыт первым.

Например, представьте, что у вас есть список элементов, и нажмите на один из они скрывают список и показывают детали элемента в другом представлении. Если у нас есть асинхронная нагрузка для деталей элемента, которая, в среднем, 400 мс, то в большинстве случаев мы можем полностью покрыть нагрузку имея 300 мс анимацию "оставить" в представлении списка и 300 мс "enter"анимация на представлении деталей элемента. Таким образом, мы обеспечиваем ощущение скольжения к пользовательскому интерфейсу, и в большинстве случаев можно избежать показаний счетчика.

Однако для этого требуется, чтобы мы инициировали асинхронную нагрузку и состояние изменить анимацию в тот же момент. Если мы используем "разрешение", вся асинхронная анимация происходит до начала анимации. Пользователь клики, видит прядильщик, затем видит переходную анимацию. Целый изменение состояния займет ~ 1000 мс, что слишком медленно.

"Разрешить" может быть полезным способом кэширования зависимостей между разные варианты, если у него была возможность не ждать на promises, но текущее поведение, всегда разрешая их до изменения состояния запуск делает его почти бесполезным, ИМО. Его следует избегать для любого зависимых, которые включают асинхронные нагрузки.

Должен ли я действительно прекратить использование resolve для загрузки некоторых данных и, скорее, начать загрузку их в соответствующий контроллер напрямую? Так что я могу обновить соответствующее представление до тех пор, пока выполняется задание и в том месте, которое я хочу в представлении, а не глобально.

4b9b3361

Ответ 1

Вы можете использовать директиву, которая прослушивает $routeChangeStart и, например, показывает элемент при его возникновении:

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

Затем вы поместите его на конкретный загрузчик вида, например:

Просмотр 1:

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

Вид 2:

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

Проблема с этим решением (и многими другими решениями в этом отношении) заключается в том, что если вы перейдете на один из маршрутов с внешнего сайта, не будет загружен предыдущий шаблон ng-view, поэтому ваша страница может быть просто пустой во время решить.

Это можно решить, создав директиву, которая будет действовать как резервный загрузчик. Он будет слушать $routeChangeStart и показывать загрузчик только в том случае, если ранее не было маршрута.

Основной пример:

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

Резервный загрузчик будет помещен вне элемента с ng-view:

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

Демо-версия всего: http://plnkr.co/edit/7clxvUtuDBKfNmUJdbL3?p=preview

Ответ 2

Я думаю, что это довольно аккуратно

app.run(['$rootScope', '$state',function($rootScope, $state){

  $rootScope.$on('$stateChangeStart',function(){
      $rootScope.stateIsLoading = true;
 });


  $rootScope.$on('$stateChangeSuccess',function(){
      $rootScope.stateIsLoading = false;
 });

}]);

а затем в представлении

<div ng-show='stateIsLoading'>
  <strong>Loading.</strong>
</div>

Ответ 3

Чтобы продолжить, Пранали ответит, как я это сделал.

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>

Ответ 4

Я опоздал на это на два года, и да, эти другие решения работают, но мне проще всего справиться со всем этим в простом блоке, вроде так

.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');
  });

}])

Вам больше ничего не нужно. Довольно легко Вот пример этого в действии.

Ответ 6

Проблема с '$ stateChangeStart' и '$ stateChangeSuccess' - это $rootScope.stateIsLoading, которая не обновляется, когда вы возвращаетесь в последнее состояние. Есть ли какое-то решение? Я также использовал:

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

и

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

но есть одна и та же проблема.