Angular Модуль загрузочного модуля пользовательского интерфейса не закрывается на задней кнопке

Я использую модуль из расширений UI Boostrap (http://angular-ui.github.io/bootstrap). Модуль фактически служит диалогом загрузки и автоматически закрывается, когда набор данных веб-службы возвращается в мой код Angular. Когда данные на этой странице загружаются автоматически, диалог открывается немедленно.

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

Я проследил это до обещания открыть диалоговое окно, которое появляется после вызова увольнения, но опять же, только когда страница загружается с помощью кнопки "Назад". Вызов отклонения никогда не закрывает ничего, потому что он еще не добавлен (я подтвердил это в отладчике).

У меня есть вопрос, как я могу справиться с этим? Есть ли твердый способ поймать завершение загрузки страницы через Angular и дважды проверить, что диалог закрыт? Есть ли лучший способ с помощью UI Bootstrap api?

Я знаю, что это довольно необычный случай, но любые мысли об этом были бы замечательными.

Спасибо!

Ответ 1

Решение @HankScorpio - это хорошо, но я думаю, что теперь может быть упрощенный вариант.

Нет необходимости хранить текущий модальный файл больше, если вы зарегистрируете прослушиватель $locationChangeStart или $routeChangeStart с помощью $uibModalStack и введите $uibModalStack.dismissAll(). $locationChangeStart имеет преимущество работы как для ngRoute, так и для uiRoute.

то есть. Если только для одной страницы, то в вашем контроллере у вас будет:

angular.module('app')
    .controller('ctrl', ['$scope', '$uibModalStack', ctrl]);

function ctrl($scope, $uibModalStack) {
    $scope.$on('$locationChangeStart', handleLocationChange);

    function handleLocationChange() {
        $uibModalStack.dismissAll();
    }
}

Если вы хотите сделать это для всех страниц, определите это в factory, который всегда загружается или просто сегмент кода app.run:

angular.module('app')
    .run(['$rootScope', '$uibModalStack', setupUibModal]);

setupUibModal($rootScope, $uibModalStack) {
    $rootScope.$on('$locationChangeStart', handleLocationChange);

    function handleLocationChange() {
        $uibModalStack.dismissAll();
    }
}

Ответ 2

Вот простое решение при использовании ui-router для изменения состояния

Закрытие модального всплывающего окна на кнопке "Назад" нажмите "angularjs"

App.run(['$rootScope', '$modalStack', function ($rootScope, $modalStack) {
   $rootScope.$on('$stateChangeStart', function (event) {
        var top = $modalStack.getTop();
        if (top) {
            $modalStack.dismiss(top.key);
        }
    })
}]);

надеюсь, что это сэкономит много времени для людей, которые ломают голову.

Ответ 3

Я столкнулся с этой проблемой. Вот как я его исправил.

1) Создайте сервис, чтобы абстрагировать открытие и закрытие модального и дорожного пути, который открыт (необходимо для шага 2). Вместо прямого вызова $modal.open() вызовите ModalService.open(). Здесь вы идете, у вас может быть тот, который я написал:

(function () {
    'use strict';

    var theModule = angular.module('services.modalService', ['ui.bootstrap']);

    theModule.factory('ModalService', function ($modal) {
        var service = {};
        var currentModal;
        var clearModal = function () {
            currentModal = undefined;
        };

        service.getCurrentModal = function () {
            return currentModal;
        };

        service.open = function (options) {
            currentModal = $modal.open(options);
            currentModal.result['finally'](clearModal);
            return currentModal;
        };

        return service;
    });
}());

2) В контроллере добавьте прослушиватель событий в $routeChangeStart, это событие будет срабатывать, когда кто-то нажимает кнопку "Назад".

$scope.$on('$routeChangeStart', function(){
  var currentModal = ModalService.getCurrentModal();
  if(angular.isDefined(currentModal)){
    currentModal.dismiss('cancel');
  }
});

3) Теперь ваши модалы должны закрываться, когда пользователь возвращается назад.

4) Наслаждайтесь.

Ответ 4

УЛУЧШЕНИЕ:

Я нашел ответ от HankScorpio лучшим из них. Я хотел бы включить этот фрагмент для тех, кто использует ui-router, и их рекомендации для модах с выражением состояния.

1) Я хотел получить результат. Наконец (...) перейти в родительское состояние; 2) Я хотел контролировать закрытие модального файла из $stateProvider config, а не путем оснащения контроллера и добавления слушателя в $routeChangeStart

Вот пример состояния, которое открывает (и закрывает) его модальный:

        .state('product.detail', {
            url: '/detail/{productId}',
            onEnter: /*open-modal logic*/,
            onExit: ['ModalService', function (ModalService) { ModalService.close()} ]                
        })

Я сделал ModalService осведомленным о $state, чтобы результат закрытия модального файла мог перейти к родительскому представлению:

а. Добавьте флаг isStateful в modalService.open(...):

service.open = function (options, isStateful) {
    currentModal = $uibModal.open(options);
    currentModal.result.finally(function () {
        clearModal(isStateful);
    });
    return currentModal;
};

чтобы clearModal вернется в предыдущее состояние:

  var clearModal = function (isStateful) {
        currentModal = undefined;
        if (isStateful)
            $state.go('^');
    };

Наконец, добавьте вышеприведенную функцию closeModal() (не закрывающую "stateful" ), просто увольнение):

  service.close = function() {
        if (currentModal) {
            currentModal.dismiss().then(function () {
                clearModal();
            })
        }
    }

Преимущество этого заключается в том, что функциональность задней кнопки управляется на уровне конфигурации состояния, а не через прослушиватель.