Повторить модальное всплывающее окно AngularJS

Я могу понять, как сделать перехватчик запроса $ http с логикой повтора, как в этом вопросе

Но я не могу понять, как сделать модальное всплывающее окно (angular-ui - bootstrap) с кнопкой повтора, которая всплывает каждый раз, когда возникает ошибка, даже неоднократно. Может ли кто-нибудь посоветовать мне?


person Alex Lapa    schedule 05.05.2014    source источник


Ответы (2)


У этого есть несколько компонентов, и вам нужно знать о цепочках обещаний, чтобы понять, как все это сочетается друг с другом. Сначала перехватчик

app.factory('RetryInterceptor', function($injector, $timeout, $q) {
  return {
   'responseError': function(rejection) {
      // Avoid circular dependency issues
      var Retry = $injector.get('Retry');
      var $http = $injector.get('$http');

      // Timeout is just to keep UI from changing too quickly
      return $timeout(angular.noop,1000).then(function() {
        return Retry.show();
      }).then(function() {
        return $http(rejection.config);
      }, function() {
        return $q.reject(rejection);
      });
    }
  }
});

зарегистрирован как

app.config(function($httpProvider) {
  $httpProvider.interceptors.push('RetryInterceptor');
});

Вышеупомянутый перехватчик responseError возвращает обещание, которое разрешено / отклонено с возвращенным обещанием Retry.open. Если это обещание будет выполнено, он повторит исходный $http запрос. Если он отклонен, то ничего не произойдет, кроме обещания, возвращенного при исходном вызове $http, будет отклонено с тем же объектом отклонения, что и без отображения диалогового окна.

Retry - это настраиваемая служба, которая предоставляет единственный метод open. Вы могли бы иметь это в перехватчике, но это сохраняет модульность:

app.service('Retry', function Retry($window, $modal) {
  this.show  = function() {
    return $modal.open({
      templateUrl: 'retry-dialog.html',
      controller: 'RetryController'
    }).result;
  }
});

Метод show возвращает обещание от службы $modal. Это обещание контролируется объектом $modalInstance, переданным контроллеру:

app.controller('RetryController', function($scope, $modalInstance) {
  $scope.retry = function() {
    // Will resolve the promise
    $modalInstance.close();
  };
  $scope.cancel = function() {
    // Will reject the promise
    $modalInstance.dismiss();
  }
});

А шаблон для модального окна может быть примерно таким:

<div class="modal-header">
  <h3>Error!</h3>
</div>
<div class="modal-body">
  <p>Something went wrong!</p>
</div>
<div class="modal-footer">
  <button class="btn btn-primary" ng-click="retry()">Retry</button>
  <button class="btn btn-danger" ng-click="cancel()">Cancel</button>
</div>

который затем разрешит обещание при нажатии кнопки «Повторить попытку» или отклонит обещание при нажатии кнопки «Отмена».

Вы можете увидеть, как все это работает в этом Plunker.

Несколько дополнительных моментов:

  • Вы можете передать подробную информацию об исходной ошибке, используя параметр resolve в $modal.open, чтобы вы могли настроить отображаемое сообщение.

  • Возможно, вы не захотите отображать диалоговое окно для всех запросов. Если, например, при загрузке шаблона для модального окна произошла ошибка, вы получите бесконечный цикл. Вы можете проверить код состояния http, чтобы отображать диалоговое окно только при определенных сбоях, или другой способ управления этим - добавить пользовательские параметры к объекту config, который вы передаете в $http, который затем можно проверить в responseError перехватчике, чтобы определить как устраняется сбой.

person Michal Charemza    schedule 05.05.2014
comment
Идеально! Имеет смысл, спасибо за объяснение. - person Alex Lapa; 06.05.2014
comment
return Retry.show (отклонение); - вам, вероятно, не нужно передавать здесь отказ, эта функция не принимает параметр. - person Alex Lapa; 06.05.2014

Посмотрите на этот модуль Angular http://ngmodules.org/modules/http-auth-interceptor Это сделано для того, чтобы перехватывать неавторизованные запросы и повторять их. Вы можете легко адаптировать этот модуль под свои нужды. Замени if (rejection.status === 401 && !rejection.config.ignoreAuthModule) своей логикой. Привязать к событию 'event:auth-loginConfirmed' с $rootScope.$on('event:auth-loginConfirmed', ...) в app.run(), чтобы открыть модальное окно. В вашем модальном введении authService factory и вызовите authService.loginConfirmed(), это повторит запрос с вашей логикой ошибки

person Didar_Uranov    schedule 05.05.2014