265

I am using Twitter bootstrap, I have specified a modal

<div class="modal hide" id="modal-item">

    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal">x</button>
        <h3>Update Item</h3>
    </div>

    <form action="http://www.website.example/update" method="POST" class="form-horizontal">

    <div class="modal-body">
        Loading content...
    </div>

    <div class="modal-footer">
        <a href="#" class="btn" data-dismiss="modal">Close</a>
        <button class="btn btn-primary" type="submit">Update Item</button>
    </div>

    </form>

</div>

And the links

<a href="http://www.website.example/item/1" data-target="#modal-item" data-toggle="modal">Edit 1</a>
<a href="http://www.website.example/item/2" data-target="#modal-item" data-toggle="modal">Edit 2</a>
<a href="http://www.website.example/item/3" data-target="#modal-item" data-toggle="modal">Edit 2</a>

When I click on any of these link for the first time, I see the correct content, but when I click on other links it shows the same content loaded for the first time, it doesn't update the content.

I want it to be updated every time its clicked.

P.S: I can easily make it work via custom jQuery function, but I want to know if it's possible with native Bootstrap modal remote function, as it should be easy enough and I guess I am just complicating things.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Dhruv Kumar Jha
  • 6,421
  • 8
  • 37
  • 48
  • 5
    Note that [`remote` Modals are deprecated as of Bootstrap v3.2.1](https://github.com/twbs/bootstrap/pull/14034) and will be gone in v4. – cvrebert Aug 27 '14 at 22:06
  • Same Fix, but modified for Bootstrap 3. Bootstrap 3 introduces namespaces. http://plnkr.co/edit/HWSgSw?p=preview – Jeff H Aug 08 '13 at 21:45

22 Answers22

446

The problem is two-fold.

First, once a Modal object is instantiated, it is persistently attached to the element specified by data-target and subsequent calls to show that modal will only call toggle() on it, but will not update the values in the options. So, even though the href attributes are different on your different links, when the modal is toggled, the value for remote is not getting updated. For most options, one can get around this by directly editing the object. For instance:

$('#myModal').data('bs.modal').options.remote = "http://website.example/item/7";

However, that won't work in this case, because...

Second, the Modal plugin is designed to load the remote resource in the constructor of the Modal object, which unfortunately means that even if a change is made to the options.remote, it will never be reloaded.

A simple remedy is to destroy the Modal object before subsequent toggles. One option is to just destroy it after it finishes hiding:

$('body').on('hidden.bs.modal', '.modal', function () {
  $(this).removeData('bs.modal');
});

Note: Adjust the selectors as needed. This is the most general.

Plunker

Or you could try coming up with a more complicated scheme to do something like check whether the link launching the modal is different from the previous one. If it is, destroy; if it isn't, then no need to reload.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
merv
  • 67,214
  • 13
  • 180
  • 245
  • Thanks, Though i understand this., I think this is the best solution (atleast for now) Hopefully they will fix this in later versions of Bootstrap. – Dhruv Kumar Jha Sep 06 '12 at 17:00
  • 1
    @VladimirStarkov Sorry about that - seems I forgot the `hide` class on the modal, so if your window was too small, the modal may have been blocking mouse events on the buttons. For some reason JSFiddle.net is really bad this morning (got a 504 trying to update), so I just redid the example on plnkr.co, which is better for AJAX anyway. – merv Nov 14 '12 at 14:08
  • This wasn't working for me on IE, so I decided to go with this answer: http://stackoverflow.com/a/14059187/271985 – Mark Mar 18 '13 at 13:06
  • @dadwithkids - I know plnkr.co doesn't work with IE, but that should only be an issue with my example, not the actual workaround. Did you try the workaround in your code? – merv Mar 18 '13 at 16:59
  • 3
    there's one other issue: the .modal-body will still have the text in it, so I added: $('#myModal .modal-body').text("Loading...") in the hidden event listener – rbp May 12 '13 at 17:03
  • 5
    `bs.modal` in `$(this).removeData('bs.modal')` worked for me with Bootstrap 3 – JacobF Dec 28 '13 at 18:34
  • 2
    Full working code for Boostrap 3 is `$('body').on('hidden.bs.modal', '.modal', function () { $(this).removeData('bs.modal'); });` – Christophe Fondacci Jan 16 '14 at 10:55
  • This work for me. I was filling the model data after ajax call by replacedata method. This was causing the error. Now, I replace replaceData method with html method and use this code $(this).removeData('modal'); – Jagz W Jan 21 '14 at 07:02
  • Adding .html('') to the end of the chain helps, as the HTML doesn't actually clear from the old modal until it's replaced by the new data. Clearing it when you remove the modal object makes for a much cleaner action. – Brian H. Feb 21 '14 at 00:26
  • @merv : very useful answer but when i used http://myip:1111 in then it will throw error.. not working. any other idea ?? – Jaydipsinh Mar 03 '14 at 14:30
  • 1
    I would also check if modal being hidden is loaded from remote source, so as not to break modals with static content: `var modalData = $(this).data('bs.modal'); if (modalData && modalData.options.remote)...` – Wojtek Kruszewski Mar 31 '16 at 14:05
  • if you have multiple modals then you can also use it like `$('body').on('hidden.bs.modal', '{particular model id/class}', function () { $(this).removeData('bs.modal'); }); ` **{particular model id/class}** replace these by your modal id/class **This will only work for {particular model id/class}.** – Ajay Patidar Oct 09 '17 at 12:37
  • @merv I've read your explanation. I'm facing what I believe is a similar problem. I'd thank you if you could take a look at it: https://stackoverflow.com/questions/47682773/jquery-result-of-script-gets-deleted-after-execution-removedata-running-on thanks beforehand – Luis Alberto Delgado de la Flo Dec 06 '17 at 20:21
171

For bootstrap 3 you should use:

$('body').on('hidden.bs.modal', '.modal', function () {
    $(this).removeData('bs.modal');
});
Camilo Nova
  • 1,889
  • 1
  • 12
  • 7
  • 17
    My hero. Love these undocumented changes. – Jorin Aug 13 '13 at 19:12
  • 2
    This helped a lot. Bootstrap 3 isn't backward compatible and most of the content on SO (or other forums) is about BS < 3, trying those solutions wastes a lot of time indeed. – Swapnil Aug 27 '13 at 21:49
  • 7
    No perfect: it briefly shows the old content before the new content. – Laurent Sep 26 '13 at 08:20
  • I ended up using this inside the callback instead: $(this).find("input[type='text'], input[type='email'], textarea").val(""); – Stone Oct 08 '13 at 04:25
  • 1
    Is there anyway to make it so that the old content is not shown briefly? – Mr B Nov 08 '13 at 12:33
  • 3
    If you want to empty the modal using the above example you should be able to add the following either before or after the `remoteData` line: `$(this).empty()` – jgillman Nov 19 '13 at 22:30
  • 11
    You shouldn't use `$(this).empty()`. The `remote` option loads the remote data into the nested ` – Gavin Feb 09 '14 at 11:07
50

For Bootstrap 3.1 you'll want to remove data and empty the modal-content rather than the whole dialog (3.0) to avoid the flicker while waiting for remote content to load.

$(document).on("hidden.bs.modal", function (e) {
    $(e.target).removeData("bs.modal").find(".modal-content").empty();
});

If you are using non-remote modals then the above code will, of course, remove their content once closed (bad). You may need to add something to those modals (like a .local-modal class) so they aren't affected. Then modify the above code to:

$(document).on("hidden.bs.modal", ".modal:not(.local-modal)", function (e) {
    $(e.target).removeData("bs.modal").find(".modal-content").empty();
});
shivam
  • 16,048
  • 3
  • 56
  • 71
slopapa
  • 2,883
  • 1
  • 16
  • 11
  • On the remote pages make sure you're not loading bootstrap, or jquery libraries. It will kill any reference and leave you with empty an empty modal. – Bankzilla Aug 18 '14 at 02:55
  • This wasn't working for me. Here is my code which is working : $(document).on("hidden.bs.modal", ".modal", function (e) { if (!$(e.target).is(".local-modal")) { $(e.target).removeData("bs.modal").find(".modal-content").empty(); } }); – Kevin Nov 21 '14 at 14:37
  • When I use `$(e.target).removeData("bs.modal").find(".modal-content").empty();` it's like my modal somehow gets hidden and only the gray overlay appears. – Axel Sep 08 '16 at 03:40
30

Thanks merv. I started tinkering around boostrap.js but your answer is a quick and clean workaround. Here's what I ended up using in my code.

$('#modal-item').on('hidden', function() {
    $(this).removeData('modal');
});
Bienvenido David
  • 4,118
  • 1
  • 25
  • 16
21

The accepted answer didn't work for me, so I went with JavaScript to do it.

<a href="/foo" class="modal-link">
<a href="/bar" class="modal-link">

<script>
$(function() {
    $(".modal-link").click(function(event) {
        event.preventDefault()
        $('#myModal').removeData("modal")
        $('#myModal').modal({remote: $(this).attr("href")})
    })
})
James Ward
  • 29,283
  • 9
  • 49
  • 85
14

This works with Bootstrap 3 FYI

$('#myModal').on('hidden.bs.modal', function () {
  $(this).removeData('bs.modal');
});
Dave Sag
  • 13,266
  • 14
  • 86
  • 134
7

My project is built in Yii & uses the Bootstrap-Yii plugin, so this answer is only relevant if you're using Yii.

The above fix did work but only after the first time the modal was shown. The first time it came up empty. I think that's because after my initiation of the code Yii calls the hide function of the modal thereby clearing out my initiation variables.

I found that putting the removeData call immediately before the code that launched the modal did the trick. So my code is structured like this...

$ ("#myModal").removeData ('modal');
$ ('#myModal').modal ({remote : 'path_to_remote'});
Sean Toru
  • 349
  • 2
  • 17
5

In Bootstrap 3.2.0 the "on" event has to be on the document and you have to empty the modal :

$(document).on("hidden.bs.modal", function (e) {
    $(e.target).removeData("bs.modal").find(".modal-content").empty();
});

In Bootstrap 3.1.0 the "on" event can be on the body :

$('body').on('hidden.bs.modal', '.modal', function () {
    $(this).removeData('bs.modal');
});
shivam
  • 16,048
  • 3
  • 56
  • 71
Romain
  • 111
  • 1
  • 5
  • The 3.2 solution was the only thing that worked properly for me in Bootstrap 3.1 - using the body approach, some of my events on modal became unhooked. – StuartQ Oct 08 '14 at 11:05
3

Why not make it more general with BS 3? Just use "[something]modal" as the ID of the modal DIV.

$("div[id$='modal']").on('hidden.bs.modal',
    function () {
        $(this).removeData('bs.modal');
    }
);
2

Only working option for me is:

$('body').on('hidden.bs.modal', '#modalBox', function () {
    $(this).remove();
});

I use Bootstrap 3 and I have a function called popup('popup content') which appends the modal box html.

Orkun Tuzel
  • 1,342
  • 10
  • 22
  • 2
    this is the only thing that worked for me with BS 3.3.6. also using handlebars template. I suggest using document instead of body however. – dbinott Feb 25 '16 at 14:49
1

Adding an $(this).html(''); to clear visible data as well, and it works pretty fine

webstr
  • 11
  • 1
1

If a remote URL is provided, content will be loaded one time via jQuery's load method and injected into the .modal-content div. If you're using the data-api, you may alternatively use the href attribute to specify the remote source. An example of this is shown below

$.ajaxSetup ({
    // Disable caching of AJAX responses
    cache: false
});
1

I've added something like this, because the older content is shown until the new one appears, with .html('') inside the .modal-content will clear the HTML inside, hope it helps

$('#myModal').on('hidden.bs.modal', function () {
   $('#myModal').removeData('bs.modal');
   $('#myModal').find('.modal-content').html('');
});
Mau GM
  • 21
  • 1
  • This is by far the simplest working answer I have found. Nothing complicated about the answer, few lines of code and easy to interpret. Worked perfectly first time withing messing with it. – Tarquin Jul 27 '16 at 23:13
0

I wrote a simple snippet handling the refreshing of the modal. Basically it stores the clicked link in the modal's data and check if it's the same link that has been clicked, removing or not the modal data.

var handleModal = function()
{
    $('.triggeringLink').click(function(event) {
        var $logsModal = $('#logsModal');
        var $triggeringLink = $logsModal.data('triggeringLink');

        event.preventDefault();

        if ($logsModal.data('modal') != undefined
            && $triggeringLink != undefined
            && !$triggeringLink.is($(this))
        ) {
            $logsModal.removeData('modal');
        }

        $logsModal.data('triggeringLink', $(this));

        $logsModal.modal({ remote: $(this).attr('href') });
        $logsModal.modal('show');
    });
};
DevAntoine
  • 1,932
  • 19
  • 24
0

For Bootstrap 3, in modal.js I changed:

$(document)
  .on('show.bs.modal',  '.modal', function () { $(document.body).addClass('modal-open') })
  .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open'); })

to

$(document)
  .on('show.bs.modal',  '.modal', function () { $(document.body).addClass('modal-open') })
  .on('hidden.bs.modal', '.modal', function () { 
    $(this).removeData('bs.modal').empty()
    $(document.body).removeClass('modal-open')
  })

(extra spacing added for clarity)

This prevents any unwanted flash of old modal content by calling empty() on the modal container as well as removing the data.

0
        $('#myModal').on('hidden.bs.modal', function () {
            $(this).removeData('modal');
        });

This one works for me.

Shawn Ang
  • 538
  • 7
  • 21
0

This other approach works well for me:

$("#myModal").on("show.bs.modal", function(e) {
    var link = $(e.relatedTarget);
    $(this).find(".modal-body").load(link.attr("href"));
});
Rhys Stephens
  • 889
  • 3
  • 20
  • 36
0
$('body').on('hidden.bs.modal', '.modal', function () {
       $("#mention Id here what you showed inside modal body").empty()
});

Which html element you want to empty like(div,span whatever).

Nikolay Kostov
  • 16,433
  • 23
  • 85
  • 123
Atul
  • 21
  • 1
  • 3
0

This one works for me:

modal

<div class="modal fade" id="searchKaryawan" tabindex="-1" role="dialog" aria-labelledby="SearchKaryawanLabel" aria-hidden="true"> <div class="modal-dialog">
<div class="modal-content">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    <h4 class="modal-title" id="SearchKaryawanLabel">Cari Karyawan</h4>
  </div>
  <div class="modal-body">
    <input type="hidden" name="location">
    <input name="cariNama" type="text" class="form-control" onkeyup="if (this.value.length > 3) cariNikNama();" />
    <div class="links-area" id="links-area"></div>
  </div>
  <div class="modal-footer">
  </div>
</div> </div></div>

script

<script type="text/javascript">$('body').on('hidden.bs.modal', '.modal', function () {  $(".links-area").empty() }); </script>

links-area is area where i put the data and need to clear

dewaz
  • 137
  • 5
0

Expanded version of accepted answer by @merv. It also checks if modal being hidden is loaded from remote source and clears old content to prevent it from flashing.

$(document).on('hidden.bs.modal', '.modal', function () {
  var modalData = $(this).data('bs.modal');

  // Destroy modal if has remote source – don't want to destroy modals with static content.
  if (modalData && modalData.options.remote) {
    // Destroy component. Next time new component is created and loads fresh content
    $(this).removeData('bs.modal');
    // Also clear loaded content, otherwise it would flash before new one is loaded.
    $(this).find(".modal-content").empty();
  }
});

https://gist.github.com/WojtekKruszewski/ae86d7fb59879715ae1e6dd623f743c5

Wojtek Kruszewski
  • 13,940
  • 6
  • 38
  • 38
-1

Tested on Bootstrap version 3.3.2

  $('#myModal').on('hide.bs.modal', function() {
    $(this).removeData();
  });
Abudayah
  • 3,816
  • 7
  • 40
  • 60
  • 1
    This is a terrible solution. Calling `.removeData()` with no parameters will tell jquery to remove all data attached to that element. As far the OP's problem is concerned, `.removeData('bs.modal')` or `.removeData('modal')` would suffice and is very safe. – Julian Paolo Dayag Aug 18 '16 at 05:37
-4

Good luck with this one:

$('#myModal').on('hidden.bs.modal', function () {
    location.reload();
});
Ibrahim Khan
  • 20,616
  • 7
  • 42
  • 55
Mappy
  • 1
  • 1