62 votes

Pourquoi la modalité multiple utilisant twitter bootstrap a obtenu l'erreur trop de récursion ?

J'essaie d'avoir une modale à l'intérieur d'une autre modale. Cependant, j'obtiens une erreur du type too much recursion dans firefox.

J'ai utilisé la dernière version de jQuery et de Twitter bootstrap mais j'ai toujours ce problème.

Voici le plunker qui montre l'erreur

Vous pouvez trouver les erreurs dans la console Uncaught RangeError: Maximum call stack size exceeded o too much recursion

Quelqu'un sait-il comment le réparer ? Merci

110voto

SmartLove Points 659

Vous pouvez appliquer la première solution de la réponse de maxisam, sans modifier les fichiers bootstrap (si vous ne pouvez pas, ou ne voulez pas).

Il suffit d'écrire cette ligne quelque part après l'inclusion des fichiers bootstrap.

$.fn.modal.Constructor.prototype.enforceFocus = function () {};

Note : Ceci a été testé avec Bootstrap 2 uniquement, pas avec Bootstrap 3.

0 votes

J'ai essayé d'utiliser Bootstrap Modal qui possède un ModalManager ( github.com/jschr/bootstrap-modal ) pour les modaux superposés. Il s'avère que vous devez créer et appeler une modale à partir d'une autre modale pour que cela fonctionne. Ceci a fait l'affaire !

2 votes

Merci, c'est beaucoup plus facile que de modifier la source et je peux l'utiliser uniquement sur les pages où c'est nécessaire.

1 votes

@Davo "Faites tout aussi simple que possible, mais pas plus simple." - Albert Einstein ; voir ma réponse pour une façon plus robuste de faire cela qui devrait préserver la fonctionnalité enforceFocus pour les autres modales.

34voto

maxisam Points 8843

Ok, il semble comme une question qui a été découvert.

(apparemment je dois utiliser le mot clé "Uncaught RangeError: le Maximum de la pile d'appels de taille dépassé" au lieu de "trop de récursivité" :( )

Voici les solutions.

1. modifier la modal.js

dans ce post, https://github.com/twbs/bootstrap/pull/5022

@onassar apporter une solution

Suivi: pour les personnes qui travaillent avec bootstrap-modale v2.2.0, dans le enforceFocus méthode, en commentant cette.$de l'élément.focus() semble pour le fixer la question.

Le résultat de ceci est la modale de ne pas me concentrer sur (pfft, je peux fais moi-même :P), et donc, les multiples modals de ne pas contester l'un de l'autre pour la mise au point (ce qui a entraîné dans une boucle infinie, et un rangerror/boucle récursive).

Espérons que cela aide :)

J'ai essayé et ça fonctionne. (plunker)

2. Utiliser un autre plugin pour répondre à cette Démo

Il semble que cela fonctionne assez bien.

3. Attendre de solution officielle.

Dans leur feuille de route, ils ne veulent réécrire cette modal plugin à un certain point.

31voto

George Jempty Points 3660

La réponse de SmartLove est malheureusement incomplète; si vous allez passer à zéro $.fn.modal.Constructor.prototype.enforceFocus , vous devriez le réinitialiser à la fermeture de votre modal; Ce qui suit est directement issu de notre code, sur lequel je n'ai aucun scrupule à mettre en production:

 // Since confModal is essentially a nested modal it's enforceFocus method
// must be no-op'd or the following error results 
// "Uncaught RangeError: Maximum call stack size exceeded"
// But then when the nested modal is hidden we reset modal.enforceFocus
var enforceModalFocusFn = $.fn.modal.Constructor.prototype.enforceFocus;

$.fn.modal.Constructor.prototype.enforceFocus = function() {};

$confModal.on('hidden', function() {
    $.fn.modal.Constructor.prototype.enforceFocus = enforceModalFocusFn;
});

$confModal.modal({ backdrop : false });
 

0 votes

Désolé, je n'ai pas été clair sur le fait que $confModal est une référence à une modale dans mon code qui a déjà été instanciée - remplacez-la par une référence à votre propre modale instanciée.

0 votes

Vous pourriez remplacer $confModal par $('modal') par exemple. Cela devrait fonctionner avec bootstrap. $('modal').on('hidden', function() { $.fn.modal.Constructor.prototype.enforceFocus = enforceModalFocusFn ; }) ;

7voto

Matyas Points 5001

4. Ou vous pouvez faire ce qui suit lors de l'affichage d'une nouvelle modale :

  1. Masquer toute modale actuellement active
  2. Afficher la nouvelle modale
  3. Lorsque vous fermez la nouvelle modale, affichez la ou les modales précédemment masquées.

    var showModal = function ($dialog) {
        var $currentModals = $('.modal.in');
        if ($currentModals.length > 0) { // if we have active modals
            $currentModals.one('hidden', function () { 
                // when they've finished hiding
                $dialog.modal('show');
                $dialog.one('hidden', function () {
                    // when we close the dialog
                    $currentModals.modal('show');
    
                });
            }).modal('hide');
        } else { // otherwise just simply show the modal
            $dialog.modal('show');
        }
    };

Note : J'utilise $.one pour que l'écouteur ne soit appliqué qu'une seule fois et ne pas se soucier de bind / unbind ( on / off )

0 votes

C'est une bonne idée, mais si la deuxième modale est une modale de chargement, vous souhaitez généralement conserver la modale précédente à l'écran.

0 votes

Le chargement est quelque chose de très général et qui recoupe l'ensemble du projet. vous pourriez peut-être créer un composant personnalisé pour cela, afin qu'il n'interfère pas avec bootstrap. (du moins, c'est ce que j'ai fait dans mon projet)

1voto

ryan Points 31

J'ai résolu ce problème en utilisant une pile.

var openmodals = [];
$(function(){
  var ts = new Date().getTime();
  $("div.modal").each(function( d ) {
    ts++;
    $( this ).data( "uid", ts );
  });

  // after closing > 1 level modals we want to reopen the previous level modal
  $('div.modal').on('show', function ( d ) {
    openmodals.push({ 'id' : $( this ).data( "uid" ), 'el' : this });
    if( openmodals.length > 1 ){
        $( openmodals[ openmodals.length - 2 ].el ).modal('hide');
    }
  });
  $('div.modal').on('hide', function ( d ) {
    if( openmodals.length > 1 ){
        if( openmodals[ openmodals.length - 1 ].id == $( this ).data( "uid" ) ){
            openmodals.pop(); // pop current modal 
            $( openmodals.pop().el ).modal('show'); // pop previous modal and show, will be pushed on show 
        }
    } else if( openmodals.length > 0 ){
        openmodals.pop(); // last modal closing, empty the stack
    } 
  });
});

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