273
votes

I am using the Twitter bootstrap Modal dialog. When I click on the submit button of the bootstrap modal dialog, it sends an AJAX request. My problem is that the modal-backdrop doesn't disappear. The Modal dialog does disappear correctly, but instead "modal-backdrop in" that creates the opacity on the screen remain

What can I do?

30
Are you using $('#myModal').modal('hide')? Can you put some code here?Pigueiras
If you are using a copy and paste from the getboostrap site itself into an html generated selector, make sure you remove the comment '<!-- /.modal -->'. Bootstrap gets confused and thinks that the comment is a second modal element. It creates another back drop for this "second" element.Jordan
@Jordan: Your comment needs to be an answer! In my case your comment was the correct solution!BlaM
I know the question is old, but today I has a similar problem, in my situation there was a miss-removal of the class "modal-lg" that was left just to "modal" creating mess when you where going to close the modal witht he keyboard/click somewhere outside.Matteo

30 Answers

582
votes

Make sure you're not replacing the container containing the actual modal window when you're doing the AJAX request, because Bootstrap will not be able to find a reference to it when you try to close it. In your Ajax complete handler remove the modal and then replace the data.

If that doesn't work you can always force it to go away by doing the following:

$('#your-modal-id').modal('hide');
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
66
votes

Make sure that your initial call to $.modal() to apply the modal behavior is not passing in more elements than you intended. If this happens, it will end up creating a modal instance, complete with backdrop element, for EACH element in the collection. Consequently, it might look like the backdrop has been left behind, when actually you're looking at one of the duplicates.

In my case, I was attempting to create the modal content on-the-fly with some code like this:

myModal = $('<div class="modal">...lots of HTML content here...</div><!-- end modal -->');
$('body').append(myModal);
myModal.modal();

Here, the HTML comment after the closing </div> tag meant that myModal was actually a jQuery collection of two elements - the div, and the comment. Both of them were dutifully turned into modals, each with its own backdrop element. Of course, the modal made out of the comment was invisible apart from the backdrop, so when I closed the real modal (the div) it looked like the background was left behind.

52
votes

I just spent way too long on this problem :)

While the other answers provided are helpful and valid, it seemed a little messy to me to effectively recreate the modal hiding functionality from Bootstrap, so I found a cleaner solution.

The problem is that there are a chain of events that happen when you call

$("#myModal").modal('hide');
functionThatEndsUpDestroyingTheDOM()

When you then replace a bunch of HTML as the result of the AJAX request, the modal-hiding events don't finish. However, Bootstrap triggers an event when everything is finished, and you can hook into that like so:

$("#myModal").modal('hide').on('hidden.bs.modal', functionThatEndsUpDestroyingTheDOM);

Hope this is helpful!

38
votes

Insert in your action button this:

data-backdrop="false"

and

data-dismiss="modal" 

example:

<button type="button" class="btn btn-default" data-dismiss="modal">Done</button>

<button type="button" class="btn btn-danger danger" data-dismiss="modal" data-backdrop="false">Action</button>

if you enter this data-attr the .modal-backdrop will not appear. documentation about it at this link :http://getbootstrap.com/javascript/#modals-usage

23
votes

I know this is a very old post but this might help. This is a very small workaround by me

$('#myModal').trigger('click');

Thats it, This should solve the issue

19
votes

If you are using a copy and paste from the getboostrap site itself into an html generated selector, make sure you remove the comment '<!-- /.modal -->'. Bootstrap gets confused and thinks that the comment is a second modal element. It creates another back drop for this "second" element.

9
votes

I suffered a similar issue: in my modal window, I have two buttons, "Cancel" and "OK". Originally, both buttons would close the modal window by invoking $('#myModal').modal('hide') (with "OK" previously executing some code) and the scenario would be the following:

  1. Open the modal window
  2. Do some operations, then click on "OK" do validate them and close the modal
  3. Open the modal again and dismiss by clicking on "Cancel"
  4. Re-open the modal, click again on "Cancel" ==> the backdrop is no longer accessible!

well, my fellow next desk saved my day: instead of invoking $('#myModal').modal('hide'), give your buttons the attribute data-dismiss="modal" and add a "click" event to your "Submit" button. In my problem, the HTML (well, TWIG) code for the button is:

<button id="modal-btn-ok" class="btn" data-dismiss="modal">OK</button>
<button id="modal-btn-cancel" class="btn" data-dismiss="modal">Cancel</button>

and in my JavaScript code, I have:

$("#modal-btn-ok").one("click", null, null, function(){
    // My stuff to be done
});

while no "click" event is attributed to the "Cancel" button. The modal now closes properly and lets me play again with the "normal" page. It actually seems that the data-dismiss="modal" should be the only way to indicate that a button (or whatever DOM element) should close a Bootstrap modal. The .modal('hide') method seems to behave in a not quite controllable way.

Hope this helps!

9
votes

This problem can also occur if you hide and then show again the modal window too rapidly. This was mentioned elsewhere for question, but I'll provide some more detail below.

The problem has to do with timing, and the fade transition. If you show a modal before the fade out transition for the previous modal is complete, you'll see this persistent backdrop problem (the modal backdrop will stay on the screen, in your way). Bootstrap explicitly does not support multiple simultaneous modals, but this seems to be a problem even if the modal you're hiding and the modal you're showing are the same.

If this is the correct reason for your problem, here are some options for mitigating the issue. Option #1 is a quick and easy test to determine if the fade transition timing is indeed the cause of your problem.

  1. Disable the Fade animation for the modal (remove the "fade" class from the dialog)
  2. Update the modal's text instead of hiding and re-showing it.
  3. Fix the timing so that it won't show the modal until it's finished hiding the previous modal. Use the modal's events to do this. http://getbootstrap.com/javascript/#modals-events

Here are some related bootstrap issue tracker posts. It is possible that there are more tracker posts than I've listed below.

9
votes

.modal('hide')

Manually hides a modal. Returns to the caller before the modal has actually been hidden (i.e. before the hidden.bs.modal event occurs).

So instead of

$('#myModal').modal('hide');
$('#someOtherSelector').trigger('click');

do

$('#myModal').modal('hide');
$('#myModal').on('hidden.bs.modal', function() {
   $('#someOtherSelector').trigger('click');
});

So you are sure to wait till the "hide" event is finished.

7
votes

Another possible mistake that could produce this problem,

Make sure you didn't included bootstrap.js script more than once in your page!

5
votes

Even I ran into a similar problem, I had the following two buttons

<button id="confirm-delete-btn" >Yes, Delete this note.</button>
<button id="confirm-delete-cancel" data-dismiss="modal">No</button>

I wanted to perform some ajax operation and on success of that ajax operation close the modal. So here is what I did.

$.ajax({
        url: '/ABC/Delete/' + self.model.get("Id")
            , type: 'DELETE'
            , success: function () {                    
                setTimeout(function () {
                    self.$("#confirm-delete-cancel").trigger("click");
                }, 1200);
            }
            , error: function () {}
        });

I triggered the click event of the 'No' button which had the data-dismiss="modal" property. And this worked :)

5
votes

use:

$('.modal.in').modal('hide') 

Source

4
votes

$('#myModal').trigger('click');

This worked for me. Its not closing because when you open the popup it triggers 2 or 3 modal-backdrops. So when you do $('#myModal')).modal('hide'); it only effect one modal-backdrop and rest remains.

3
votes

This solution is for Ruby on Rails 3.x and a js.erb file that rebuilds part of the DOM including the modal. It works regardless if the ajax call came from the modal or from a different part of the page.

if ($("#my-modal").attr("aria-hidden") === "false") {
  $("#my-modal").modal('hide').on('hidden.bs.modal', function (event) {
    functionThatEndsUpDestroyingTheDOM();
  });
} else {
  functionThatEndsUpDestroyingTheDOM();
}

Thanks to @BillHuertas for the starting point.

3
votes

Adding data-dismiss="modal" on any buttons in my modal worked for me. I wanted my button to call a function with angular to fire an ajax call AND close the modal so I added a .toggle() within the function and it worked well. (In my case I used a bootstrap modal and used some angular, not an actual modal controller).

<button type="button" class="btn btn-primary" data-dismiss="modal"
ng-click="functionName()"> Do Something </button>

$scope.functionName = function () {
angular.element('#modalId').toggle();
  $.ajax({ ajax call })
}
3
votes

After applying the top rated solution I've had a problem that it breaks future modals opening properly. I've found my solution which works good

        element.on("shown.bs.modal", function () {
            if ($(".modal-backdrop").length > 1) {
                $(".modal-backdrop").not(':first').remove();
            }
            element.css('display', 'block');
        });
2
votes

updatepanel issue.

My issue was due to the updatepanel placement. I had the entire modal in the updatepanel. If you declare the modal outside the updatepanel and just have say, the modal body, in the update panel, then the $('#myModalID').modal('hide'); worked.

2
votes

Another point of view to this question. (I'm using the bootstrap.js version 3.3.6)

I mistaken initialize modal both by manually in javascript:

$('#myModal').modal({
   keyboard: false
})

and by using

data-toggle="modal"

in this button like example below (shown in document)

<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">Launch demo modal</button>

so the result its create two instance of

<div class="modal-backdrop fade in"></div>

append to the body of my html when open the modal. This can be the cause when closing the modal by using function:

$('#myModal').modal('hide');

it remove only one backdrop instance (as show above) so the backdrop won't disappeared. But it did disappear if you use data-dismiss="modal" add on html as show in bootstrap doc.

So the solution to my problem is to only initialize modal manually in javascript and not using data attribute, In this way I can both close the modal manually and by using data-dismiss="modal" features.

Hope this will help if you encountered the same problem as me.

2
votes

FYI in case someone runs into this still... I've spent about 3 hours to discover that the best way to do it is as follows:

$("#my-modal").modal("hide");
$("#my-modal").hide();
$('.modal-backdrop').hide();
$("body").removeClass("modal-open");

That function to close the modal is very unintuitive.

1
votes

In .net MVC4 project I had the modal pop up (bootstrap 3.0) inside an Ajax.BeginForm( OnComplete = "addComplete" [extra code deleted]). Inside the "addComplete" javascript I had the following code. This solved my issue.

$('#moreLotDPModal').hide();

$("#moreLotDPModal").data('bs.modal').isShown = false;

$('body').removeClass('modal-open');

$('.modal-backdrop').remove();

$('#moreLotDPModal').removeClass("in");

$('#moreLotDPModal').attr('aria-hidden', "true");

1
votes

I had the same problem. I discovered it was due to a conflict between Bootstrap and JQueryUI.

Both use the class "close". Changing the class in one or the other fixes this.

1
votes

Using toggle instead of hide, solved my problem

1
votes

Make sure you are not using the same element Id / class elsewhere, for an element unrelated to the modal component.

That is.. if you are identifying your buttons which trigger the modal popups using the class name 'myModal', ensure that there are no unrelated elements having that same class name.

1
votes

for me, the best answer is this.

<body>
<!-- All other HTML -->
<div>
    ...
</div>

<!-- Modal -->
<div class="modal fade" id="myModal">
    ...
</div>

Modal Markup Placement Always try to place a modal's HTML code in a top-level position in your document to avoid other components affecting the modal's appearance and/or functionality.

from this SO answer

1
votes

I had the same problem when trying to submit the form. The solution was to change the button type from submit to button and then handle the button click event like so:

'click .js-save-modal' () {
    $('#myFormId').submit();
    $('#myModalId').modal('hide');
}
0
votes

I had this very same issue.

However I was using bootbox.js, so it could have been something to do with that.

Either way, I realised that the issue was being caused by having an element with the same class as it's parent. When one of these elements is used to bind a click function to display the modal, then the problem occurs.

i.e. this is what causes the problem:

<div class="myElement">
    <div class="myElement">
        Click here to show modal
    </div>
</div>

change it so that the element being clicked on doesn't have the same class as it's parent, any of it's children, or any other ancestors. It's probably good practice to do this in general when binding click functions.

0
votes

I am working with Meteor and I just got the same problem. The cause of my bug was this:

{{#if tourmanager}}
    {{>contactInformation tourmanager}}
{{else}}
    <a href="#addArtistTourmanagerModal" data-toggle="modal"><i class="fa fa-plus"></i> Tourmanager toevoegen</a>
    {{>addArtistTourmanagerModal}}
{{/if}}

As you can see I added the modal in the else, so when my modal updated the contactinformation the if had another state. This caused the modal template to be left out of the DOM just before it would close.

The solution: move the modal out of the if-else:

{{#if tourmanager}}
    {{>contactInformation tourmanager}}
{{else}}
    <a href="#addArtistTourmanagerModal" data-toggle="modal"><i class="fa fa-plus"></i> Tourmanager toevoegen</a>
    {{>addArtistTourmanagerModal}}
{{/if}}
0
votes
//Create modal appending on body
myModalBackup = null;
$('#myModal').on('hidden.bs.modal', function(){
       $('body').append(myModalBackup.clone());
    myModalBackup = null;
});

//Destroy, clone and show modal
myModalBackup = $('#myModal').clone();
myModalBackup.find('.modal-backdrop').remove();
$('#myModal').modal('hide').remove();
myModalBackup.find('.info1').html('customize element <b>1</b>...');
myModalBackup.find('.info2').html('customize element <b>2</b>...');                             
myModalBackup.modal('show');

fiddle --> https://jsfiddle.net/o6th7t1x/4/

0
votes

the initial value of your data-backdrop attribute can be

"static","true", "false" .

static and true add the modal shadow, while false disable the shadow, so you just need to change this value with the first click to false . like this:

$(document).on('ready',function(){
	
	var count=0;
	
$('#id-which-triggers-modal').on('click',function(){
		
		if(count>0){
		
			$(this).attr('data-backdrop','false')
		}
		count++;
});


});
0
votes

I had the modal backdrop screen freeze problem but in a slightly different scenario: When 2 back to back modals were being displayed. e.g. The first would ask for confirmation to do something and after the 'confirm' button was clicked, the action would come across an error and the 2nd modal was going to be displayed to popup the error message. The 2nd modal backdrop would freeze the screen. There were no clashes in class names or id's of the elements.

The way the problem was fixed was to give the browser enough time to deal with the modal backdrop. Instead of immediately taking the action after the 'confirm' was clicked, give the browser say 500ms to hide the 1st modal and clean up the backdrop etc - then take the action which would end up in showing the error modal.

<button type="button" class="btn btn-red" data-dismiss="modal" on-tap="_dialogConfirmed">Confirm</button>
...

The _dialogConfirmed() function has the following code:

    var that = this;

    setTimeout(function () {
      if (that.confirmAction) {
        (that.confirmAction)();
        that.confirmAction = undefined;
      }
    }, 500);

I'm guessing the other solutions worked because they took enough extra time giving the browser the needed cleanup time.