Twitter Bootstrap / jQuery - How to temporarily prevent the modal from being closed?

Note: This solution is targeting twitter bootstrap 2.x! See this answer (just below) for differences according to bootstrap 3.


Extending bootstrap modal functionality without modifying original source.

Thanks to @David and his suggestion at How to Extend Twitter Bootstrap Plugin I finally got it to work. It is a slightly modified version of his solution with modal "lock" added. I post it as a additional answer since I think it may could be a starting point for others that like me have struggled hard with this issue.

// save the original function object
var _superModal = $.fn.modal;

// add locked as a new option
$.extend( _superModal.defaults, {
    locked: false
});

// create a new constructor
var Modal = function(element, options) {
    _superModal.Constructor.apply( this, arguments )
}

// extend prototype and add a super function
Modal.prototype = $.extend({}, _superModal.Constructor.prototype, {
    constructor: Modal

    , _super: function() {
        var args = $.makeArray(arguments)
        // call bootstrap core
        _superModal.Constructor.prototype[args.shift()].apply(this, args)
    }

    , lock : function() {
        this.options.locked = true
    }

    , unlock : function() {
        this.options.locked = false
    }

    , hide: function() {
        if (this.options.locked) return
        this._super('hide')
    }
});

// override the old initialization with the new constructor
$.fn.modal = $.extend(function(option) {
    var args = $.makeArray(arguments),
    option = args.shift()

    // this is executed everytime element.modal() is called
    return this.each(function() {
        var $this = $(this)
        var data = $this.data('modal'),
            options = $.extend({}, _superModal.defaults, $this.data(), typeof option == 'object' && option)

        if (!data) {
            $this.data('modal', (data = new Modal(this, options)))
        }
        if (typeof option == 'string') {
            data[option].apply( data, args )
        }
    });
}, $.fn.modal);

With this technique it should not be nessecary to alter bootstrap.js, and the same functionality can more easily be shared among bootstrap projects. This method should be applicable to all the other bootstrap plugins. Have so far only tried with button though, but I cant se why it shouldnt.

see working fiddle -> http://jsfiddle.net/Sz7ZS/


There is an easier way to do it. This bootstrap pull request explains a little more. The solution disables all methods for closing the modal (keyboard, mouse click, close button).

All you have to do to disable closing the modal is:

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

To enable closing again:

$('#myModal').data('bs.modal').isShown = true;

Example

Here is some sample code that works in conjunction with a jQuery get:

// disable closing the modal
$('#myModal').data('bs.modal').isShown = false;

// Send an HTTP GET request to the server - replace this with getJSON, post or ajax as needed
$.get( "ajax/test.html", function( data ) {
  // enable closing the modal
  $('#myModal').data('bs.modal').isShown = true;

  // Do something with the data
  $( ".result" ).html( data );
});

You are not the only one who are missing that feature. I think bootstrap sometimes is too "minimalistic", the people behind has the idea a lot should be done in the "implementation layer", but it is to no use when the bootstrap jQuery plugins themselves makes it impossible!

You have to implement the functionality yourself, like this :

in bootstrap.js v2.1.1 modal begins at line 61.

in Modal.prototype, add two functions, lock and unlock, so it looks like this (I show here only the beginning of modal.prototype, becuase it is too much code)

  Modal.prototype = {

      constructor: Modal

      //add this function
    , lock: function () {
        this.options.locked = true
      }

      //add this function
    , unlock: function () {
        this.options.locked = false
      }

    , toggle: function () {
    ... 
    ...

Then, also in Modal.prototype, find the function hide, and add a line so it looks like this (again, only top of hide is showed)

, hide: function (e) {
    e && e.preventDefault()

    var that = this

    //add this line
    if (that.options.locked) return

    e = $.Event('hide')
    ...
    ...

And finally, alter $.fn.modal.defaults to :

  $.fn.modal.defaults = {
      backdrop: true
    , keyboard: true
    , show: true
    , locked: false //this line is added
  }

Now you have on-the-fly lock/unlock functionality in your bootstrap modal, preventing the user from closing the modal at critical moments.

Example :

This is an altered version of "Live Demo" from http://twitter.github.com/bootstrap/javascript.html#modals

<!-- Button to trigger modal -->
<a href="#myModal" role="button" class="btn" data-toggle="modal">Launch demo modal</a>

<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
    <h3 id="myModalLabel">Modal header</h3>
  </div>
  <div class="modal-body">
    <p>One fine body…</p>
  </div>
  <div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <button class="btn btn-primary" onclick="$('#myModal').modal('lock');">lock</button>
    <button class="btn btn-primary" onclick="$('#myModal').modal('unlock');">unLock</button>
  </div>
</div>
<script type="text/javascript">

I have inserted two buttons, "lock" and "unlock" - when clicked, they set the modal in either locked or normal mode (the settings it is initialised with)

Edit, in your case, you just have to call lock/onlock when doing ajax :

$("myModal").modal('lock');
$.ajax({
    url: url,
    ...
    ...
    , success(html) {
       ...
       ...
       $("#myModal").modal('unlock');
    }
});