Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular UI Bootstrap Module Not Closing on Back Button

I'm using a module from the UI Boostrap extensions (http://angular-ui.github.io/bootstrap). The module actually serves as a loading dialog and is automatically closed when a set of web service data is returned to my Angular code. As the data on this page is loaded automatically the dialog comes up immediately.

All this works great when I hit the page in question for the the first time or simply refresh it. The problem occurs when I go to a deeper page and then try and navigate back to the original page (with the dialog) via the browser's back button. The dialog never goes away despite all the fact that all the data is returned and the module's dismiss() call has been made.

I've traced this down to the promise to open the dialog appears to be happening after the dismiss call but, again, only when the page is loaded via the back button. The dismiss call never closes anything because it hasn't been added yet (I've confirmed this in the debugger).

The question I have is how could I handle this? Is there a solid way to catch the completion of the page loading via Angular and double check that the dialog closed? Is there a better way via UI Bootstrap's api?

I know this is rather unusual case but any thoughts on it would be great.

Thanks!

like image 882
Siegmund Nagel Avatar asked Apr 08 '15 23:04

Siegmund Nagel


3 Answers

@HankScorpio's solution is good, but I think there may be a simplified option now.

There is no need to store the current modal anymore, if you register either a $locationChangeStart or $routeChangeStart listener with $uibModalStack injected and call $uibModalStack.dismissAll(). $locationChangeStart has the benefit of working for both ngRoute and uiRoute.

i.e. If only for the one page, then in your controller you'd have:

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

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

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

If you want to do this for all pages then define this in a factory that is always loaded or just an app.run code segment:

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

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

    function handleLocationChange() {
        $uibModalStack.dismissAll();
    }
}
like image 177
Mark van Proctor Avatar answered Nov 17 '22 04:11

Mark van Proctor


Here is the simple solution when using ui-router for state change

Closing modal popup on the back button click in angularjs

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

hope this will save lot of time for people who are breaking heads

like image 5
VR1256 Avatar answered Nov 17 '22 06:11

VR1256


I've run into this same problem. Here's how I fixed it.

1) Create a service to abstract the opening and closing of a modal and track which one is open (necessary for step 2). Instead of calling $modal.open() directly, call ModalService.open(). Here you go, you can have the one I wrote:

(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) In a controller, add an event listener to $routeChangeStart, this event will fire whenever someone hits the back button.

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

3) Your modals should now close when a user hits back.

4) Enjoy.

like image 4
HankScorpio Avatar answered Nov 17 '22 05:11

HankScorpio