Bootstrap: modal('show') after a modal('hide') doesn't work

Created on 21 Jun 2012  Â·  18Comments  Â·  Source: twbs/bootstrap

immediately after hiding a modal, if a show call is issued it doesn't work
e.g.

$('#show_modal').click(function(){
   $('#test-modal').modal('show')
   $('#test-modal').modal('hide')
   $('#test-modal').modal('show')
})

​
Looks like end effect should be a modal dialog shown, but instead modal is hidden with a black screen see it in action here http://jsfiddle.net/anuraguniyal/qzAmP/

For time being I am working around it by issuing a setTimeout of 1000 msec, because looks like bootstrap takes 500 msec to hide modal in a timeout

js

Most helpful comment

I was just searching for this myself. Ended up with the following solution:

var hideInProgress = false;
var showModalId = '';

function showModal(elementId) {
    if (hideInProgress) {
        showModalId = elementId;
    } else {
        $("#" + elementId).modal("show");
    }
};

function hideModal(elementId) {
    hideInProgress = true;
    $("#" + elementId).on('hidden.bs.modal', hideCompleted);
    $("#" + elementId).modal("hide");

    function hideCompleted() {
        hideInProgress = false;
        if (showModalId) {
            showModal(showModalId);
        }
        showModalId = '';
        $("#" + elementId).off('hidden.bs.modal');
    }
};

The hideModal function sets a flag that it is currently hiding a modal. When it is done it resets the flag. If a modal tries to open while closing is in progress, the id is saved and when closing is complete it shows the modal. This ensures that as long as you call "hideModal" before "showModal", the modal is closed before the next one is opened.

All 18 comments

Have you tried using

$('#test-modal').show().on('shown', function() { 
    $('#test-modal').modal('hide') 
});

I haven't tried that but that is also not possible generally because hide may be called from one function and show will be called from another function e.g. If I have a single modal dialog for displaying error, I got an error and displayed a msg with a button to take action, action button hides modal calls another function which has again some error and it shows the modal which doesn't come up as mentioned above

The issue is that .modal() is async, so those three calls will be fired one after another without waiting the other one to finish, thus causing issues.

Even using toggle causes issue in this scenario. The most sane thing would be to patch the modal proto to add a callback.

Hi, I have tried this as follows.

$(".btn-plus").click(function(){
$('#new_passenger').modal("show").on('hide', function() {
$('#new_passenger').modal('hide')
});
});

I worked.
sorry for my english.. =)

was a bug with that – fixed in 2.3

Still there in 2.3.1 : http://jsfiddle.net/ngegC/

My solution with the same problem was put a settimeout in the next 'hide' and 'show':
$('#show_modal').click(function(){
$('#test-modal').modal('show')
setTimeout(function(){$('#test-modal').modal('hide')}, 10)
setTimeout(function(){$('#test-modal').modal('show')}, 900)
})
I know that this isn't a good solution but resolve my problem.
Excuse my English I'm learning...

As eskimoblood indicates, this is still an issue with 2.3.1. Using a test for if the modal is visible and if so using a on "hidden" should provide a reasonable work around.

Solution about every bug like this one is three steps:

1 - Use bootstrap-modal.js
2 - Set max backdrop like this: $.fn.modalmanager.defaults.backdropLimit = 1;
3 - Use this modal header (check stackable topic):
http://jschr.github.io/bootstrap-modal/
4 - Don Use Button tag in order to open modals, use Links (check stackable topic):
http://jschr.github.io/bootstrap-modal/

That tips solves that and more bugs about bootstrap modals

Sorry my english and hope it helps

Ugh...
My workaround was to do a $('body') and see if it has the class 'modal-open'. If not -> open the modal. If yes, subscribe the .one('hidden.bs.modal', function(){ open the modal}) and call close() first

I used the $timeout service as I'm using angular. It works most of the times, but the only problem is choosing a reasonable timeout value, since it can vary a lot with browsers/ environments.

I was just searching for this myself. Ended up with the following solution:

var hideInProgress = false;
var showModalId = '';

function showModal(elementId) {
    if (hideInProgress) {
        showModalId = elementId;
    } else {
        $("#" + elementId).modal("show");
    }
};

function hideModal(elementId) {
    hideInProgress = true;
    $("#" + elementId).on('hidden.bs.modal', hideCompleted);
    $("#" + elementId).modal("hide");

    function hideCompleted() {
        hideInProgress = false;
        if (showModalId) {
            showModal(showModalId);
        }
        showModalId = '';
        $("#" + elementId).off('hidden.bs.modal');
    }
};

The hideModal function sets a flag that it is currently hiding a modal. When it is done it resets the flag. If a modal tries to open while closing is in progress, the id is saved and when closing is complete it shows the modal. This ensures that as long as you call "hideModal" before "showModal", the modal is closed before the next one is opened.

I had to tweak @kimsy's version in case a show gets called before the shown is complete. Here is a fiddle version with it working .

I created a Typescript version as well that handles not showing a Modal if the hide is called before the show is ever triggered

export module BootstrapExtension {
    let _actionInProgress = false;
    let _nextActionQueue = [] as ActionQueueInstance[];

    export type ModalAction = "hide" | "show";
    export interface ModalOptions {
        backdrop?: boolean | "static";
        keyboard?: boolean;
        focus?: boolean;
        show?: boolean;
    }

    interface ActionQueueInstance {
        modal: JQuery;
        options: ModalOptions | ModalAction;
    }

    /**
     * Lot's of fun issues arise when attempting to display a modal more than once, before it finishes loading
     * https://github.com/twbs/bootstrap/issues/3902
     * http://jsfiddle.net/daryllabar/npn4wvjm/
     * @param modal Id of the modal, or JQuery object of the modal
     * @param options
     */
    export function safeModal(modalOrId: string | JQuery, options?: ModalOptions | ModalAction): JQuery {
        if (!modalOrId) {
            return modalOrId as JQuery;
        }
        const modal = typeof modalOrId === "string" ? $(`#${modalOrId}`) : modalOrId;
        const action = getAction(options);

        if (_actionInProgress) {
            if (action === "hide") {
                for (let i = 0; i < _nextActionQueue.length; i++) {
                    const futureAction = _nextActionQueue[i];
                    if (futureAction.modal === modal && getAction(futureAction.options) === "show") {
                        // hide called when show is waiting to execute, clear both
                        _nextActionQueue.splice(i, 1);
                        return modal;
                    }
                }
            }
            _nextActionQueue.push({
                modal: modal,
                options: options
            });
            return modal;
        }

        const postEventName = getPostEventName(action);
        _actionInProgress = true;
        modal.on(postEventName, clearInProgress);
        modal.modal(options);

        function clearInProgress() {
            _actionInProgress = false;
            modal.off(postEventName, clearInProgress);
            if (_nextActionQueue.length > 0) {
                const next = _nextActionQueue.shift();
                safeModal(next.modal, next.options);
            }
        }

        return modal;
    };

    function getAction(options: ModalOptions | ModalAction): ModalAction {
        if (isModalAction(options)) {
            return options;
        } else if (!options) {
            return "show";
        } else {
            return options.show ? "show" : "hide";
        }
    }

    function getPostEventName(action: ModalAction): string {
        const prefix = action === "hide" ? "hidden" : "shown";
        return prefix + ".bs.modal";
    }

    export function isModalAction(arg: any): arg is ModalAction {
        switch (arg) {
            case "hide":
            case "show":
            case "toggle":
                return true;
            default:
                return false;
        }
    }
}

As a workaround you can remove "fade" class from your modal. If you need to prevent user to close the modal on click you need to add data-backdrop="static" attribute to your modal.

The below statements show how to open/reopen Modal without using bootstrap.

Add two classes in css
1) .hide_block{
display:none !important;
}
2) .display_block{
display:block !important;
}

And then use the below jQuery to reopen the modal if it is closed.

$("#Modal").removeClass('hide_block');
$("#Modal").addClass('display_block');
$("Modal").show("slow");

It worked fine for me :)

Based on this answer I've made it with this code:

$(modal_selector).on('hidden.bs.modal', function(e){ $(modal_selector).data('bs.modal', null); });

It looks that everytime the modal is hidden, it must to be reinitialized, so, you catch "hidden.bs.modal" and reinitialize the modal with .data('bs.modal', null);

It worked fine for me :)

Execution of the .modal() method takes time. If during execution the next modal() is called, it has no effect (see documentation). For a please wait modal I created following solution

var showPleaseWait=0;

function pleaseWaitInitialize()
{
    $('#pleaseWaitDialog').on('shown.bs.modal', function (e) {
        if (!showPleaseWait)
        {
            $("#pleaseWaitDialog").modal("hide");
        }
   });
}

function pleaseWaitShow()
{
    showPleaseWait=1;
    $("#pleaseWaitDialog").modal("show");
}

function pleaseWaitHide()
{
    showPleaseWait=0;
    $("#pleaseWaitDialog").modal("hide");
}

In this way whichever if the modal("hide") in pleaseWaitHide() has no effect because .modal("show") isn't ready, the 2nd modal("hide") in the ready call back is taking effect.
Of course this concept can be extended to your problem

$('#show_modal').click(function () { $('#test-modal').modal('show'); $('#test-modal').on('shown.bs.modal', function () { $('#test-modal').modal('hide'); $('#test-modal').on('hidden.bs.modal', function () { $('#test-modal').modal('show'); }); }); });

https://getbootstrap.com/docs/3.4/javascript/#modals-methods

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fohlsom picture fohlsom  Â·  3Comments

IamManchanda picture IamManchanda  Â·  3Comments

leomao10 picture leomao10  Â·  3Comments

devdelimited picture devdelimited  Â·  3Comments

kamov picture kamov  Â·  3Comments