【问题标题】:Angular UI Bootstrap Module Not Closing on Back ButtonAngular UI Bootstrap 模块未在后退按钮上关闭
【发布时间】:2015-06-14 03:35:09
【问题描述】:

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

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

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

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

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

谢谢!

【问题讨论】:

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


【解决方案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();
    }
}

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

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

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

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

【讨论】:

  • 请注意,根据 ui-bootstrap 的版本,您可以使用 $modalStack 而不是 $uibModalStack(当前为 $uibModalStack)
  • 如果您希望后退按钮关闭对话框但实际上不返回历史记录,您可以检查$uibModalStack.getTop() 是否返回任何内容,只有在这种情况下才会关闭 and also i> event.preventDefault()event 被传递给handleLocationChange())。
【解决方案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】:

    改进:

    我发现 HankScorpio 的答案是最好的。我想为那些使用 ui-router 的人提供这个 sn-p 以及他们对 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 以便关闭模式的结果可以跳转到父视图:

    一个。向 modalService.open(...) 添加 isStateful 标志:

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

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

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题。这是我修复它的方法。

      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) 享受。

      【讨论】:

      • 这是否适用于从目标页面导航的页面或用于目标页面的页面?问题不在于我要清理的页面,而是在目标页面上加载的不同事件序列。
      • 我实际上最终做了与你类似的事情,但我在页面底部的空白跨度上挂上了一个 ng-show 处理程序(完全 hack)。我希望有更好的方法,但它确实“有效”。
      • 重新阅读您的原始帖子,听起来这个问题的原因是 100% 的时间(加载该页面时)打开模式弹出窗口,即使它不需要,是对吗?
      • 不完全是:当页面加载时,对话框会弹出 100% 的时间,但这是预期的。该页面必须从服务器重建状态和所需数据,因此出现对话框。问题是使用后退按钮时,目标页面永远不会关闭对话框,即使在所有状态重建完成之后也是如此。这又是因为 UI 引导程序颠倒了对话框的打开和关闭承诺的运行顺序。当页面由于后退按钮导航而加载时会发生这种情况。
      • 我不确定我是否遵循。所以你的代码试图在打开之前关闭模式?能否提供一些示例代码?
      猜你喜欢
      • 1970-01-01
      • 2015-04-02
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 2014-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多