Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: Multiple popups can't be closed (sort of) #3131

Closed
jorenp opened this issue Feb 17, 2015 · 23 comments
Closed

bug: Multiple popups can't be closed (sort of) #3131

jorenp opened this issue Feb 17, 2015 · 23 comments
Labels
needs: reply the issue needs a response from the user
Milestone

Comments

@jorenp
Copy link

jorenp commented Feb 17, 2015

Type: bug

Platform: all

The issue only happens when multiple popups are opened in quick succession. In this case, the backdrop div remains visible after the last popup has closed. We've been able to repro the issue on iOS 8 and on the desktop (chrome and IE11).

I've included a short codepen to illustrate the issue.
http://codepen.io/anon/pen/VYXLjv

@olore
Copy link

olore commented Mar 7, 2015

Some kind of timing issue. The result is 3 divs with classes: 'popup-showing active'. The popupStack isn't updated quickly enough, so each new modal isn't aware of the previous ones.

@ideadx
Copy link

ideadx commented Jul 15, 2015

This issue is still on 1.0.1, I get multiple popups
$ionicPopup.alert({
title: title,
template: body
});

@vool
Copy link

vool commented Jul 31, 2015

I am having the same issue here, I am on 1.5.5
.k

@sharvit
Copy link

sharvit commented Jul 31, 2015

This is how i handle it:

    .factory('SecuredPopups', [
        '$ionicPopup',
        '$q',
        function ($ionicPopup, $q) {

            var firstDeferred = $q.defer();
            firstDeferred.resolve();

            var lastPopupPromise = firstDeferred.promise;

            return {
                'show': function (method, object) {
                    var deferred = $q.defer();

                    lastPopupPromise.then(function () {
                        $ionicPopup[method](object).then(function (res) {
                            deferred.resolve(res);
                        });
                    });

                    lastPopupPromise = deferred.promise;

                    return deferred.promise;
                }
            };
        }
    ])

    // ...

    var alertPopup = SecuredPopups.show('alert', {
     title: 'Don\'t eat that!',
     template: 'It might taste good'
   });

   alertPopup.then(function(res) {
     console.log('Thank you for not eating my delicious ice cream cone');
   });

@hackape
Copy link

hackape commented Sep 24, 2015

@sharvit Thanks for your solution, it helps alot!

@lfv89
Copy link

lfv89 commented Oct 9, 2015

This is a common issue that begs for a default solution.

Thanks @sharvit

EDIT: typo

@Florian9-3
Copy link

@sharvit Thanks for the solution. Opening the popup works, but how can I close it and open another?

@sharvit
Copy link

sharvit commented Oct 13, 2015

@Florian9-3 that way you can get the close method with the promise:

.factory('SecuredPopups', [
    '$ionicPopup',
    '$q',
    function ($ionicPopup, $q) {

        var firstDeferred = $q.defer();
        firstDeferred.resolve();

        var lastPopupPromise = firstDeferred.promise;

        // Change this var to true if you want that popups will automaticly close before opening another
        var closeAndOpen = false;

        return {
            'show': function (method, object) {
                var deferred = $q.defer();
                var closeMethod = null;
                deferred.promise.isOpen = false;
                deferred.promise.close = function () {
                    if (deferred.promise.isOpen && angular.isFunction(closeMethod)) {
                        closeMethod();
                    }
                };

                if (closeAndOpen && lastPopupPromise.isOpen) {
                    lastPopupPromise.close();
                }

                lastPopupPromise.then(function () {
                    deferred.promise.isOpen = true;
                    var popupInstance = $ionicPopup[method](object);

                    closeMethod = popupInstance.close;
                    popupInstance.then(function (res) {
                        deferred.promise.isOpen = false;
                        deferred.resolve(res);
                    });
                });

                lastPopupPromise = deferred.promise;

                return deferred.promise;
            }
        };
    }
])

// ...

var alertPopupA = SecuredPopups.show('alert', {
 title: 'AAA',
 template: 'AAA'
});

var alertPopupB = SecuredPopups.show('alert', {
 title: 'BBB',
 template: 'BBB'
});

alertPopupA.then(function(res) {
 console.log('AAA Finished!');
});

alertPopupB.then(function(res) {
 console.log('BBB Finished!');
});

console.log('A is: ' + alertPopupA.isOpen ? 'open' : 'closed');
console.log('B is: ' + alertPopupB.isOpen ? 'open' : 'closed');

alertPopupA.close();

I didn't test it, let me know if its work

@Florian9-3
Copy link

@sharvit Works like a charm. Thanks so much.

@maikokuppe
Copy link

It seems to me that @sharvit's solution only allows for one extra layer of popups. I wanted a generalized solution allowing for an arbitrary amount of popups, and arrived at one which works as follows:
Open a popup A the usual way. Before the next popup B is opened, A is moved to a stack (and closed in the ionic way, I call it 'soft-close'). When B resolves, A is extracted from the stack and reopened. When finally A resolves, this will be propagated to the factory caller (not on the first 'soft-close').

app.factory 'Popup', ($q, $rootScope, $ionicPopup) ->

  stack: []

  show: (options) ->
    deferred = $q.defer()
    # Soft-close currently open popup. This will not resolve deferred.promise.
    @stack[0].close('soft') if @stack.length
    # This timeout hack is necessary because ionic's popup logic would fail without it
    setTimeout =>
      # Pass data through to $ionicPopup service
      currentPopup = $ionicPopup.show options
      currentPopup.options = options
      currentPopup.deferred = deferred
      # Pass through close method
      deferred.promise.close = ->
        currentPopup.close()
      # Add / remove popup from stack
      @stack.unshift currentPopup
      currentPopup.then @handleCloseEvent(currentPopup)
    , 0

    deferred.promise

  close: ->
    # Close all popups in the stack
    angular.forEach @stack, (popup) -> popup.close()

  handleCloseEvent: (popup) ->
    (data) =>
      unless data == 'soft'
        # Remove popup from stack
        @stack.shift()
        if @stack.length
          # Reopen previously closed popup from stack and update the corresponding stack element
          reopenedPopup = $ionicPopup.show @stack[0].options
          reopenedPopup.options = @stack[0].options
          reopenedPopup.deferred = @stack[0].deferred
          @stack[0] = reopenedPopup
          # Set a handler for the new popup promise
          reopenedPopup.then @handleCloseEvent(reopenedPopup)
        # Propagate close event to the app
        popup.deferred.resolve data

I didn't test this with more than two overlapping popups, but it should work in theory ;)

@jtomaszewski
Copy link

+1

@crazybaud
Copy link

@ajoslin this issue should be opened again, or at least a workaround should be documented somewhere. Do you know a good place where we can add it ?

@mlynch mlynch reopened this Dec 18, 2015
@mlynch mlynch added this to the 1.3 milestone Dec 18, 2015
@matiasurbano
Copy link

@sharvit thanks !!

@pluswave
Copy link

pluswave commented Mar 7, 2016

+1

@mushopea
Copy link

Hey guys, I get "TypeError: $ionicPopup[method] is not a function" when I try to implement the factory @sharvit posted. Does anybody have a workaround?

@jgw96
Copy link
Contributor

jgw96 commented Apr 21, 2016

Hello! Are you all still having this issue? Thanks!

@jgw96 jgw96 added the needs: reply the issue needs a response from the user label Apr 21, 2016
@jgw96
Copy link
Contributor

jgw96 commented Apr 26, 2016

Hello! As it has been a little while since there was any activity on this issue I will be closing it. Thanks for using ionic!

@jgw96 jgw96 closed this as completed Apr 26, 2016
@crazybaud
Copy link

crazybaud commented Apr 27, 2016

Hello! Are you all still having this issue? Thanks!

@jgw96 yes of course, we have a "dirty" workaround in place (like everyone I think). Do you need something ? May we help ? Did you ask because something change in a new release ?

@sugir93
Copy link

sugir93 commented May 16, 2016

am still facing the same issue....can anyone help me to fix this problem..
Tanx in advance:-)

@gynekolog
Copy link

@mushopea
You must specified method:
var alertPopupA = SecuredPopups.show('alert', {
title: 'AAA',
template: 'AAA'
});

@sugir93
Copy link

sugir93 commented May 18, 2016

but am calling the ionic popup using normal js.
so is how to call ur SecuredPopups outside the angular service.

thanks in advance

@gynekolog
Copy link

Create factory like @sharvit, paste SecuredPopups in your controller definition and create $scope.popup there.

$scope.alertPopupA = function() {
    var popup = SecuredPopups.show('alert', {
        title: 'AAA',
        template: 'AAA',
        scope: $scope
    });
}

Now you can call $scope.alertPopupA(); in controller or ng-click="alertPopupA()" in template.

@sugir93
Copy link

sugir93 commented May 18, 2016

tanks for ur help 👍

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Sep 8, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs: reply the issue needs a response from the user
Projects
None yet
Development

No branches or pull requests