Angular UI Bootstrap模块未关闭后退按钮

时间:2015-04-08 23:34:19

标签: angularjs twitter-bootstrap angular-ui-bootstrap

我正在使用UI Boostrap扩展模块(http://angular-ui.github.io/bootstrap)。该模块实际上用作加载对话框,并在将一组Web服务数据返回到我的Angular代码时自动关闭。当自动加载此页面上的数据时,会立即显示对话框。

当我第一次点击有问题的页面或者只是刷新它时,这一切都很有效。当我进入更深的页面,然后尝试通过浏览器的后退按钮导航回原始页面(使用对话框)时,会出现问题。尽管返回了所有数据并且已经进行了模块的dismiss()调用,但对话框永远不会消失。

我已经将此跟踪到打开对话框的承诺似乎在解雇调用之后发生,但是,仅当通过后退按钮加载页面时。解雇调用永远不会关闭任何东西,因为它尚未添加(我已在调试器中确认了这一点)。

我的问题是如何处理?是否有一种可靠的方法来捕获通过Angular完成页面加载并仔细检查对话框是否已关闭?有没有更好的方法通过UI Bootstrap的api?

我知道这是一个非常不寻常的案例,但对此的任何想法都会很棒。

谢谢!

4 个答案:

答案 0 :(得分:6)

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

如果要对所有页面执行此操作,请在始终加载的工厂或app.run代码段中定义此项:

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

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

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

答案 1 :(得分:5)

  

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

希望这会为那些打破头脑的人节省大量时间

答案 2 :(得分: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)享受。

答案 3 :(得分:0)

改进:

我发现HankScorpio的答案是最好的。我想为使用ui-router的用户及其对stateful modals的建议添加此代码段。

1)我希望result.finally(...)跳转到父状态;
2)我想控制从$ stateProvider配置关闭模态,而不是通过绑定控制器并向$ 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()函数(不是“有状态”关闭,只是解雇):

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

这样做的好处是后退按钮功能是在状态配置级别控制的,而不是通过监听器控制的。