【问题标题】:Need to close a modal on state exit需要在状态退出时关闭模式
【发布时间】:2014-05-05 19:37:33
【问题描述】:

我正在使用 UI-Router 和 angular bootstrap-ui。我有一个状态设置来创建模式“onEnter”。当我尝试关闭模式“onExit”时,我现在遇到了问题。这是基本状态。当输入“items.detail”时它将打开一个模态,当该模态关闭或关闭时它将转换为“items”。

.state('items.detail', {
    url: '/{id}',
    onEnter: function ($stateParams, $state, $modal, $resource) {
        var modalInstance = $modal.open({
            templateUrl: 'views/modal/item-detail.html',
            controller: 'itemDetailCtrl'
        })
        .result.then(function () {
            $state.transitionTo('items');
        }, function () {
            $state.transitionTo('items');
        });
    }
})

我已经尝试过像这样使用 onExit 处理程序。但是无法从该处理程序访问 modalInstance 或模式所在的范围。我尝试注入的所有内容都未定义。

.state('items.detail', {
    url: '/{id}',
    onEnter: function ($stateParams, $state, $modal, $resource) {
        var modalInstance = $modal.open({
            templateUrl: 'views/modal/item-detail.html',
            controller: 'itemDetailCtrl'
        })
        .result.then(function () {
            $state.transitionTo('items');
        }, function () {
            $state.transitionTo('items');
        });
    },
    onExit: function ($scope) {
        controller: function ($scope, $modalInstance, $modal) {
            $modalInstance.dismiss();
        };
    }
})

我尝试在模态控制器中监听状态变化。

$scope.$on('$stateChangeStart', function() {
    $modalInstance.dismiss();
});

我在 $scope.$on 和 $rootScope.$on 上都试过了,这两种方法都有效,但每次我在任何状态之间转换时都会调用它们。但是,这仅在我打开模式后才会发生。

如果最后一点不清楚...当我刷新我的 Angular 应用程序时,我可以在所有其他状态之间转换而不会调用此侦听器事件,但是在我打开该模式后,我的所有状态更改都会被该侦听器调用,即使在模态关闭之后。

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    虽然这个问题很老了,因为我最近遇到了同样的情况,并想出了一个更好的解决方案,但我还是决定在这里分享我的结果。关键是将 $modal.open 服务移动到状态的 resolve 部分,这是一种预加载数据和 $promise 服务,然后将解析的 modelInstance 注入到 onEnter、onExit 等。代码可能如下所示:

    .state('items.detail', {
        url: '/{id}',
        resolve: {
            modalInstance: function(){
                return $modal.open({
                    templateUrl: 'views/modal/item-detail.html',
                    controller: 'itemDetailCtrl'
                })
            },
        },
        onEnter: function ($stateParams, $state, modalInstance, $resource) {
            modalInstance 
            .result.then(function () {
                $state.transitionTo('items');
            }, function () {
                $state.transitionTo('items');
            });
        },
        onExit: function (modalInstance) {
            if (modalInstance) {
                modalInstance.close();
            }
        }
    })
    

    【讨论】:

    • 这应该是被接受的答案。它完全实现了作者想要的
    • 对于任何想通过 ui-router 的 $previousState 看到这项工作的人,只需在 onEnter 中记录之前的状态,如下所示:onEnter: function($previousState) { $previousState.memo('modalInvoker'); } - 无需其他更改。然后,您可以根据需要使用按钮或其他任何东西返回到该状态。
    【解决方案2】:

    我认为您可以更好地组织您的模态打开行为。我不会在状态定义中使用 onEnter 和 onExit 处理程序。相反,最好定义应该处理模态的控制器:

    .state('items.detail', {
        url: '/{id}',
        controller:'ItemDetailsController',
        template: '<div ui-view></div>'
    })
    

    然后定义你的控制器:

    .controller('ItemDetailsController', [
        function($stateParams, $state, $modal, $resource){
            var modalInstance = $modal.open({
                templateUrl: 'views/modal/item-detail.html',
                controller: 'ModalInstanceCtrl',
                size: size,
                resolve: {
                    itemId: function () {
                       return $stateParams.id;
                }
             modalInstance.result.then(function () {
                    $state.go('items');
                }, function () {
                    $state.go('items');
             });
          }
        });       
        }
    ])
    

    然后定义你的 ModalInstanceCtrl:

    .controller('ModalInstanceCtrl', [ 
        function ($scope, $modalInstance, itemId) {
    
            //Find your item from somewhere using itemId and some services
            //and do your stuff
    
    
            $scope.ok = function () {
                $modalInstance.close('ok');
            };
    
            $scope.cancel = function () {
               $modalInstance.dismiss('cancel');
            };
        };
    ]);
    

    这样你的模态将在 ModalInstanceCtrl 中关闭,你就不用担心 state 的 onExit 处理程序了。

    关于 $scope 上添加的监听器。似乎当您添加侦听器并且在状态更改时从不删除它,这会导致内存泄漏,并且每次您的应用程序更改其状态时都会执行处理程序函数!所以最好去掉那个事件监听器,因为你实际上并不需要它。

    【讨论】:

    • 谢谢,这似乎是一个更好的解决方案,并且易于实施。
    • 欢迎,祝你好运:)
    • 等一下,我想,我一时误解了正在发生的事情。现在我下班回家了,它并没有关闭状态变化的模式,我猜它从来没有或者我改变了一些东西。无论如何,当状态离开时,这其中的哪一部分会关闭模式?
    • 这些情况确实有效。我试图捕捉的情况是,如果用户在模式打开或修改 url 时点击后退按钮。在这些情况下,它将进入新状态,同时保持模式打开。
    • 但是 onEnter 是 ui-router 文档中推荐的,专门解决了“我如何告诉 ui-router 我想要某个状态来打开对话框或模态”的问题换掉 ui-view 模板?”。
    【解决方案3】:

    你可以通过监听$stateChangeStart event来防止离开状态

    $scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
        console.log('$stateChangeStart', toState);
        if (toState.name != 'items.list'){
            event.preventDefault();
            var top = $modalStack.getTop();
            if (top) {
                $modalStack.dismiss(top.key);
            }
            $state.go('items.list');
        }
    });
    

    【讨论】:

    • 所有这些事件都在 $rootScope 级别触发。 [引]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多