72

I just started a new project with the new Twitter Bootstrap release : bootstrap 3. I can't make the Modal work in the remote mode. I just want that when I click on a link it shows the modal with the content of the remote url. It works but the modal layout is completely destroyed.

Here is a link to a jsfiddle : http://jsfiddle.net/NUCgp/5/

The code :

<a data-toggle="modal" href="http://fiddle.jshell.net/Sherbrow/bHmRB/0/show/" data-target="#myModal">Click me !</a>

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                 <h4 class="modal-title">Modal title</h4>

            </div>
            <div class="modal-body"><div class="te"></div></div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary">Save changes</button>
            </div>
        </div>
        <!-- /.modal-content -->
    </div>
    <!-- /.modal-dialog -->
</div>
<!-- /.modal -->

Can anyone make this simple example work ?

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
user2707039
  • 760
  • 1
  • 6
  • 8

9 Answers9

112

Regarding the remote option for modals, from the docs:

If a remote URL is provided, content will be loaded via jQuery's load method and injected into the root of the modal element.

That means your remote file should provide the complete modal structure, not just what you want to display on the body.

Bootstrap 3.1 Update:

In v3.1 the above behavior was changed and now the remote content is loaded into .modal-content

See this Demo fiddle

Boostrap 3.3 Update:

This option is deprecated since v3.3.0 and has been removed in v4. We recommend instead using client-side templating or a data binding framework, or calling jQuery.load yourself.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
omma2289
  • 54,161
  • 8
  • 64
  • 68
  • 7
    You don't need to put the contents of the modal on your original page, just the source itself. See here: http://jsfiddle.net/NUCgp/59/ – rybo111 Oct 07 '13 at 10:50
  • Do you think this code: http://plnkr.co/edit/HWSgSw?p=preview can works with bootstrap 3 final? Thanks – Khrys Oct 14 '13 at 13:10
  • @Khrys it would if you follow the instruction I gave, your external html files should include the complete modal structure – omma2289 Oct 14 '13 at 16:08
  • 12
    Why the heck do I have to replicate all the same html 10 times for 10 dialogs ONLY because they put the html loaded into the modal-content and not body? Are they stupid?! – Pascal Apr 08 '14 at 18:41
  • @rybo111 your jsfiddle does not work anymore. Likely because in `v3.1 the above behavior was changed and now the remote content is loaded into .modal-content`. – dbasch Jul 12 '14 at 07:59
  • @koala_dev your remote content should not include the ` – dbasch Jul 12 '14 at 08:08
  • @dbasch Thanks, when I updated the answer with v3.1 changes I forgot to update the fiddle. I have fixed it now. – omma2289 Jul 12 '14 at 17:28
  • 1
    How can we change the modal size depending on the remote content? – Alex Jose Feb 09 '15 at 08:43
  • 16
    UPDATE: "This option is deprecated since v3.3.0 and will be removed in v4. We recommend instead using client-side templating or a data binding framework, or calling jQuery.load yourself." – Thiago Apr 07 '15 at 14:09
  • What if you only want to have one modal, not several? – i am me Mar 11 '16 at 00:30
  • This bit me today, I have a hyperlink with `href`, `data-toggle="modal"` and `data-target` set, and am unfortunately restricted to using Bootstrap 3.0.0. It seems that the default behaviour in that version was `remote=true` for relative links only, so the end result was the entirety of my modal's content was being clobbered by the content pointed to by the `href`. – Ian Kemp Apr 08 '16 at 12:05
  • 6
    I don't understand *why* it has been deprecated... This is extensively useful and despite depreciation, I feel like using it, improving it, making it work (and I actually do)! It would be great to have some deeper explanations on this, in order to decide whether making a plugin would be a good idea or not... – Augustin Riedinger Feb 21 '17 at 09:55
  • @AugustinRiedinger I guess it's because of the events side of things. Bootstrap modals publish `show.bs.modal` and `shown.bs.modal` however there's no event published after `shown.bs.modal` to say that the content has been re-loaded – andrewm Feb 08 '18 at 19:56
29

For Bootstrap 3

The workflow I had to deal with was loading content with a url context that could change. So by default setup your modal with javascript or the href for the default context you want to show :

$('#myModal').modal({
        show: false,
        remote: 'some/context'
});

Destroying the modal wouldn't work for me because I wasn't loading from the same remote, thus I had to :

$(".some-action-class").on('click', function () {
        $('#myModal').removeData('bs.modal');
        $('#myModal').modal({remote: 'some/new/context?p=' + $(this).attr('buttonAttr') });
        $('#myModal').modal('show');
});

This of course was easily refactored into a js library and gives you a lot of flexibility with loading modals

I hope this saves someone 15 minutes of tinkering.

zorkle
  • 369
  • 3
  • 6
  • Not 100% sure why - but I had to cleanup my DOM after the data cleanup. Added this line: $('#mymodal .modal-content').html(""); – Froyke Aug 19 '14 at 15:58
  • 4
    `$('#myModal').on('hide.bs.modal', function () { $('#myModal').removeData('bs.modal'); $('#myModal .modal-content').html(''); });` Works for me. – Scott Flack Sep 24 '14 at 07:29
18

If you don't want to send the full modal structure you can replicate the old behaviour doing something like this:

// this is just an example, remember to adapt the selectors to your code!
$('.modal-link').click(function(e) {
    var modal = $('#modal'), modalBody = $('#modal .modal-body');

    modal
        .on('show.bs.modal', function () {
            modalBody.load(e.currentTarget.href)
        })
        .modal();
    e.preventDefault();
});
MM.
  • 2,653
  • 4
  • 26
  • 36
  • why can't press 'escape' or click on the backdrop to close the dialog? keyboard option is set to true by default. – Warrio Mar 15 '17 at 11:30
13

Here's my solution (leveraging a few above) that makes use of BS3's own structure to re-instate the old remote loading behaviour. It should be seamless.

I'm going to keep the code variable heavy and descriptive to keep things understandable. I'm also assuming the presence of JQuery. Javascript heavy lifter types will handily streamline the code.

For reference here's a link that invokes a BS3 modal:

<li><a data-toggle="modal" href="terms.html" data-target="#terms">Terms of Use</a></li>

In youre Javascript you're going to need the following.

// Make sure the DOM elements are loaded and accounted for
$(document).ready(function() {

  // Match to Bootstraps data-toggle for the modal
  // and attach an onclick event handler
  $('a[data-toggle="modal"]').on('click', function(e) {

    // From the clicked element, get the data-target arrtibute
    // which BS3 uses to determine the target modal
    var target_modal = $(e.currentTarget).data('target');
    // also get the remote content's URL
    var remote_content = e.currentTarget.href;

    // Find the target modal in the DOM
    var modal = $(target_modal);
    // Find the modal's <div class="modal-body"> so we can populate it
    var modalBody = $(target_modal + ' .modal-body');

    // Capture BS3's show.bs.modal which is fires
    // immediately when, you guessed it, the show instance method
    // for the modal is called
    modal.on('show.bs.modal', function () {
            // use your remote content URL to load the modal body
            modalBody.load(remote_content);
        }).modal();
        // and show the modal

    // Now return a false (negating the link action) to prevent Bootstrap's JS 3.1.1
    // from throwing a 'preventDefault' error due to us overriding the anchor usage.
    return false;
  });
});

We're just about there. One thing you may want to do is style the modal body with a max-height, so that long content will scroll.

In your CSS, you'll need the following:

.modal-body{
    max-height: 300px;
    overflow-y: scroll;
}

Just for refference I'll include the modal's HTML, which is a knock-off of every Bootsrap Modal Example you've ever seen:

<div id="terms" class="modal fade">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h3 id="termsLabel" class="modal-title">TERMS AND CONDITIONS</h3>
      </div>
      <div class="modal-body">
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
      </div>
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->
TheAdventurist
  • 146
  • 1
  • 2
9

I did this:

$('#myModal').on 'shown.bs.modal', (e) ->  
  $(e.target).find('.modal-body').load('http://yourserver.com/content')
MBHNYC
  • 1,268
  • 1
  • 13
  • 25
8

As much as I dislike modifying Bootstrap code (makes upgrading more difficult), you can simply add ".find('.modal-body') to the load statement in modal.js as follows:

// original code
// if (this.options.remote) this.$element.load(this.options.remote)

// modified code
if (this.options.remote) this.$element.find('.modal-body').load(this.options.remote)
esvendsen
  • 1,492
  • 1
  • 12
  • 16
5

Here is the method I use. It does not require any hidden DOM elements on the page, and only requires an anchor tag with the href of the modal partial, and a class of 'modalTrigger'. When the modal is closed (hidden) it is removed from the DOM.

  (function(){
        // Create jQuery body object
        var $body = $('body'),

        // Use a tags with 'class="modalTrigger"' as the triggers
        $modalTriggers = $('a.modalTrigger'),

        // Trigger event handler
        openModal = function(evt) {
              var $trigger = $(this),                  // Trigger jQuery object

              modalPath = $trigger.attr('href'),       // Modal path is href of trigger

              $newModal,                               // Declare modal variable

              removeModal = function(evt) {            // Remove modal handler
                    $newModal.off('hidden.bs.modal');  // Turn off 'hide' event
                    $newModal.remove();                // Remove modal from DOM
              },

              showModal = function(data) {             // Ajax complete event handler
                    $body.append(data);                // Add to DOM
                    $newModal = $('.modal').last();    // Modal jQuery object
                    $newModal.modal('show');           // Showtime!
                    $newModal.on('hidden.bs.modal',removeModal); // Remove modal from DOM on hide
              };

              $.get(modalPath,showModal);             // Ajax request

              evt.preventDefault();                   // Prevent default a tag behavior
        };

        $modalTriggers.on('click',openModal);         // Add event handlers
  }());

To use, just create an a tag with the href of the modal partial:

<a href="path/to/modal-partial.html" class="modalTrigger">Open Modal</a>
just a slime
  • 470
  • 5
  • 12
  • This is Excellent Brandon Fitzpatrick. I am calling ASP.Net MVC partial view, it is getting loaded and able to show that popup. I have an issue, my jquery code is not binding to my button, textbox. Can you please tell me how to assign button click event to the button, I have done like below in my partialview.cshtml – Karthikeyan Nov 28 '15 at 12:27
  • It's hard to say without seeing more code, but here are some suggestions. I'm assuming both your button and script tag is inside the modal content. 1. Make sure that the #btnSaveComment element been rendered before the click event is registered. If $('#btnSaveComment').length===0, the element has not been added to the DOM. 2. If the mime type of the requested document isn't text/html, jquery will not evaluate the loaded scripts. If that's the case, specify that it's html using the lower-level $.ajax() function instead of $.get(). (http://stackoverflow.com/a/2203816/856389). – just a slime Nov 30 '15 at 19:08
5

another great and easy way is to have a blind modal in your layout and call it if neccessary.

JS

  var remote_modal = function(url) {
    // reset modal body with a spinner or empty content
    spinner = "<div class='text-center'><i class='fa fa-spinner fa-spin fa-5x fa-fw'></i></div>"

    $("#remote-modal .modal-body").html(spinner)
    $("#remote-modal .modal-body").load(url);
    $("#remote-modal").modal("show");
  }

and your HTML

 <div class='modal fade' id='remote-modal'>
    <div class='modal-dialog modal-lg'>
      <div class='modal-content'>
        <div class='modal-body'></div>
        <div class='modal-footer'>
          <button class='btn btn-default'>Close</button>
        </div>
      </div>
    </div>
  </div>
</body>

now you can simply call remote_modal('/my/url.html') and the content gets displayed inside of the modal

Tim Kretschmer
  • 2,272
  • 1
  • 22
  • 35
0

I do it this way:

<!-- global template loaded in all pages // -->
     <div id="NewsModal" class="modal fade" tabindex="-1" role="dialog" data-ajaxload="true" aria-labelledby="newsLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                        <h3 class="newsLabel"></h3>
                    </div>
                    <div class="modal-body">
                            <div class="loading">
                                <span class="caption">Loading...</span>
                               <img src="/images/loading.gif" alt="loading">
                        </div>
                    </div>
                    <div class="modal-footer caption">
                        <button class="btn btn-right default modal-close" data-dismiss="modal">Close</button>
                    </div>
                </div>
            </div>
        </div>

Here is my a href:

<a href="#NewsModal" onclick="remote=\'modal_newsfeed.php?USER='.trim($USER).'&FUNCTION='.trim(urlencode($FUNCTIONCODE)).'&PATH_INSTANCE='.$PATH_INSTANCE.'&ALL=ALL\'
                                        remote_target=\'#NewsModal .modal-body\'" role="button" data-toggle="modal">See All Notifications <i class="m-icon-swapright m-icon-dark"></i></a>
yardpenalty.com
  • 1,244
  • 2
  • 17
  • 32