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

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

About this issue

  • Original URL
  • State: closed
  • Created 12 years ago
  • Comments: 22 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Have you tried using

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

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… =)

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.

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 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.

$('#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

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…

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 😃

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

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 😃

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

Hi guys, in my case, I removed class=“fade” of my modal, and worked! I don’t understood what, but worked.

before:

<div class="modal fade vertical-center col-md-12 col-md-offset-5" id="loading" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> ... </div>

AFTER:

<div class="modal vertical-center col-md-12 col-md-offset-5" id="loading" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">...</div>

then, I used: $('#loading').modal('toggle')