Why does multiple modal using twitter bootstrap got error too much recursion?

JavascriptJqueryTwitter Bootstrap

Javascript Problem Overview


I try to have a modal inside another modal. However, I got an error like too much recursion in firefox.

I used the latest jQuery and Twitter bootstrap but still have this problem.

Here is the plunker that shows the error

You can find errors in console Uncaught RangeError: Maximum call stack size exceeded or too much recursion

Does anyone know how to fix it? Thanks

Javascript Solutions


Solution 1 - Javascript

You can apply the first solution of maxisam answer, without modifying bootstrap files (if you can not, or don't want to).

Just write this line somewhere after bootstrap files have been included.

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

Note: This has been tested with Bootstrap 2 only, not with Bootstrap 3.

Solution 2 - Javascript

Ok, it seems like an issue that has been discovered.

(apparently I should use key word "Uncaught RangeError: Maximum call stack size exceeded" instead of "too much recursion" :( )

Here are the solutions.

1. modify the modal.js

in this post, https://github.com/twbs/bootstrap/pull/5022

@onassar bring up a solution

> Follow up: for anyone working with bootstrap-modal v2.2.0, in the > enforceFocus method, commenting out that.$element.focus() seems to fix > the issue. > > The result of this is the modal's don't get focused upon (pfft, I can > do that myself :P), and thus, the multiple modals don't challenge > one-another for focus (which resulted in an infinite loop, and a > rangerror/recursive loop). > > Hope that helps :)

I tried and it works. (plunker)

2. Use another plugin to address this Demo

It seems like it works pretty well.

3. Wait for official solution.

In their roadmap, they do want to rewrite this modal plugin at some point.

Solution 3 - Javascript

SmartLove's answer unfortunately falls short; if you're going to no-op $.fn.modal.Constructor.prototype.enforceFocus, you should reset it when your modal closes; the following is directly from our code, about which I have no qualms putting into 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 });

Solution 4 - Javascript

4. Or you could do the following when showing a new modal:

  1. Hide any modal that is currently active

  2. Show the new modal

  3. When you close the new modal, show previously hidden modal(s)

     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: I use $.one to only have the listener applied once and not to care about bind/unbind (on/off)

Solution 5 - Javascript

For Bootstrap 4, replace : $.fn.modal.Constructor.prototype.**enforceFocus** By $.fn.modal.Constructor.prototype.**_enforceFocus**

Solution 6 - Javascript

Try the following css. It worked for me.

span.select2-container {
    z-index:10050;
}

Solution 7 - Javascript

Bootstrap 5 version of @Dexygen answer:

const enforceModalFocusFn = bootstrap.Modal.prototype._enforceFocus ;    
const onMyModalHidden = function(){
   bootstrap.Modal.prototype._enforceFocus = enforceModalFocusFn;
}

//let modalElem = ...;
modalElem.addEventListener('hidden.bs.modal', onMyModalHidden);
bootstrap.Modal.prototype._enforceFocus = function () {};

Important note: You have to override the function before the modal is shown. That means i.e. on 'show.bs.modal'. If you initialize override later, i.e. on 'shown.bs.modal' it wont work, because the original function was allready passed.

The same works for offcanvas (that was what I needed), just change .Modal to .Offcanvas and _enforceFocus to _enforceFocusOnElement

Solution 8 - Javascript

I solved this using a stack.

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

Solution 9 - Javascript

You can omit: tabindex="-1", at the top of modal, you can open the modal in the way: $('#modal').show(); and close: $('#modal').hide();

Note: JQuery is required for this to work.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmaxisamView Question on Stackoverflow
Solution 1 - JavascriptTony - Currentuser.ioView Answer on Stackoverflow
Solution 2 - JavascriptmaxisamView Answer on Stackoverflow
Solution 3 - JavascriptDexygenView Answer on Stackoverflow
Solution 4 - JavascriptMatyasView Answer on Stackoverflow
Solution 5 - JavascriptbbastouView Answer on Stackoverflow
Solution 6 - JavascriptNidhinView Answer on Stackoverflow
Solution 7 - JavascriptSolilimView Answer on Stackoverflow
Solution 8 - JavascriptRyanView Answer on Stackoverflow
Solution 9 - JavascriptFede LleoView Answer on Stackoverflow