35 votes

Twitter Bootstrap / jQuery - Comment empêcher temporairement la fermeture du modal?

Je suis en utilisant Twitter Bootstrap des modaux, avec les options par défaut où vous pouvez cliquer sur la toile de fond ou appuyez sur la touche [Esc] pour fermer la modale.

Cependant, lorsque je lance une opération d'ajax dans la modale je souhaite désactiver le modal à partir de la fermeture d'une quelconque façon. J'ai donc désactiver les boutons et masquer la modale du bouton fermer, mais je ne peux pas comprendre comment désactiver la toile de fond et la touche [Esc].

J'ai essayé:

$('#myModal').modal({
    backdrop: 'static',
    keyboard: false
});

Mais cela ne semble pas fonctionner à la volée.

J'aurai aussi besoin de ré-activer la toile de fond et le clavier une fois l'opération ajax est fini.

17voto

davidkonrad Points 14038

Remarque: Cette solution est de ciblage twitter bootstrap 2.x! Voir cette réponse (juste en dessous) pour les différences selon le bootstrap 3.


L'extension de bootstrap modal de la fonctionnalité sans modification de code source original.

Grâce à @David, et sa suggestion sur la Façon de Prolonger Twitter Bootstrap Plugin , j'ai enfin réussi à le faire fonctionner. C'est une version légèrement modifiée de sa solution modale "lock", a ajouté. Je poste en tant que réponse supplémentaire car je pense qu'il peut pourrait être un point de départ pour d'autres personnes qui comme moi ont lutté avec ce problème.

// 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);

Avec cette technique, il ne devrait pas être nessecary de modifier bootstrap.js et la même fonctionnalité peut plus facilement être partagées entre les amorçage de projets. Cette méthode devrait être applicable à tous les autres bootstrap plugins. N'ont jusqu'à présent essayé avec bouton, mais je ne peux pas se pourquoi il ne faut pas.

voir le travail de violon -> http://jsfiddle.net/Sz7ZS/

10voto

qingu Points 198

Il y a un moyen plus facile de le faire. Cette bootstrap pull request explique un peu plus. La solution désactive toutes les méthodes pour fermer la modale (clavier, souris, cliquez sur, bouton de fermeture).

Tout ce que vous avez à faire pour désactiver la fermeture de la modale est:

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

Afin de permettre la fermeture de nouveau:

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

Exemple

Voici un exemple de code qui fonctionne en conjonction avec un jQuery obtenir:

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

9voto

davidkonrad Points 14038

Vous n'êtes pas le seul à qui il manque de la fonctionnalité. Je pense que bootstrap est parfois trop "minimaliste", les gens derrière l'idée a beaucoup doit être fait dans la "mise en œuvre de la couche", mais il est d'aucune utilité lorsque le bootstrap, jQuery plugins eux-mêmes rend impossible!

Vous devez implémenter la fonctionnalité vous-même, comme ceci :

en bootstrap.js v2.1.1 modal commence à la ligne 61.

en Modal.prototype, ajouter deux fonctions, lock et onluck, de sorte qu'il ressemble à ceci (que je montre ici que le début d' modal.prototype, parce que c'est trop de 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 () {
    ... 
    ...

Puis, aussi Modal.prototype, trouver la fonction hide, et ajouter une ligne qui ressemble à ceci (encore une fois, seul le haut de la peau est montré)

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

    var that = this

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

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

Et enfin, alter $.fn.modal.defaults à la :

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

Maintenant que vous avez sur la volée de verrouiller/déverrouiller les fonctionnalités de votre modal bootstrap, empêchant l'utilisateur de fermer la modale à des moments critiques.

Exemple :

Ceci est une version modifiée de "Live Demo" de l' 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">

J'ai inséré deux boutons, "lock" et "déverrouiller" - quand on clique dessus, ils ont mis le modal en soit verrouillé ou en mode normal (les réglages, il est initialisé avec)

Modifier, dans votre cas, vous avez juste à appeler de verrouillage/onlock quand on fait de l'ajax :

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

9voto

alez Points 41

Vous pouvez créer une variable isBlocked que vous pouvez définir lors des appels AJAX sur true, puis vous pouvez la vérifier sur l'événement de masquage modal bootsrap de cette façon:

 $('#myModal').on('hide.bs.modal', function (e) {
      //Prevent modal from closing is isBlocked is true
      if(isBlocked) return e.preventDefault();
})
 

Je pense que cette façon est plus facile que d'étendre Bootsrap, j'espère que cela aide quelqu'un: D

5voto

ragamufin Points 1379

Merci @davidkonrad pour votre travail sur ce. J'ai essayé de l'implémenter en tant que bien, et il semble que les choses ont changé avec bootstrap 3. Maintenant, au lieu de:

_superModal.defaults

il est maintenant attaché à l'constructeur de sorte que vous avez à faire

_superModal.Constructor.DEFAULTS

Aussi le constructeur a changé, ce qui signifiait que j'avais de le copier et de le modifier ce qui est loin d'être idéale. Au lieu de cela, je suis venu avec le code suivant qui fonctionne et ne copie pas le constructeur et doit être plus infaillible si bootstrap changements à l'avenir. Allez-y:

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

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

// capture the original hide
var _hide = _superModal.Constructor.prototype.hide;
// console.log('HIDE:', _hide);

// add the lock, unlock and override the hide of modal
$.extend(_superModal.Constructor.prototype, {
    // locks the dialog so that it cannot be hidden
    lock: function() {
        // console.log('lock called');
        // console.log('OPTIONS',this.options);
        this.options.locked = true;
    }
    // unlocks the dialog so that it can be hidden by 'esc' or clicking on the backdrop (if not static)
    ,unlock: function() {
        // console.log('unlock called');
        this.options.locked = false;
    }
    // override the original hide so that the original is only called if the modal is unlocked
    ,hide: function() {
        // console.log('hide called');
        if (this.options.locked) return;

        _hide.apply(this, arguments);
    }
});

Afin de verrouiller le modal:

$('#dlg').modal('lock');

et pour le déverrouiller:

$('#dlg').modal('unlock');

Yay!!!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X