how to create a jquery counter function for modal switching - javascript

i got the following problem, i would like to create a counter function to switch between modals so i can re-use the function on multiple pages, i'm fighting my way trough the internet but can't find the solution, i tried multiple options, but it only switched trough the first 2 modals, also when i check the log, my counter variable don't get past 1 (first click).
i started with this
var counter = 0;
var step = 1;
var prev = 0;
$( document ).ready(function() {
$('.button-'+counter).click(function() {
counter++;
prev = counter - step;
$('.window-'+prev).modal('hide');
$('.window-'+counter).modal('show');
console.debug(counter, prev);
});
//$('.modal-header > .close').click(function() {
// counter = 0;
//});
});
then after some research i ended up with this, but it does exactly the same thing
var counter = 0;
var step = 1;
var prev = 0;
$( document ).ready(function() {
$('#addproductnext').each(function() {
$(this).on('click', function() {
counter++;
prev = counter - step;
console.log(counter, prev);
if($('#addproductwindow').hasClass('window-'+prev)) {
$('.window-'+prev).modal('hide');
$('.window-'+counter).modal('show');
};
});
});
This is my quick fix for now, but i dont think it's neat
$( document ).ready(function() {
$('.button-0').click(function() {
$('.window-0').modal('hide');
$('.window-1').modal('show');
});
$('.button-1').click(function() {
$('.window-1').modal('hide');
$('.window-2').modal('show');
});
$('.button-2').click(function() {
$('.window-2').modal('hide');
$('.window-3').modal('show');
});
$('.button-3').click(function() {
$('.window-3').modal('hide');
$('.window-4').modal('show');
});
//$('.modal-header > .close').click(function() {
// counter = 0;
//});
});
Here is what my html looks like (php function)
<div class="modal fade window-' . $number . '" id="' . $name . '" tabindex="-1" role="dialog" aria-labelledby="' . $name . '" aria-hidden="true" data-backdrop="' . $backdrop . '">
<div class="modal-dialog ' . $class . '" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deletemessage">' . $header .'</strong></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
BODY
</div>
</div>
</div>
</div>

<button class="button-modal">Button 1</button>
<button class="button-modal">Button 2</button>
<button class="button-modal">Button 3</button>
<script>
var counter = 0;
var step = 1;
var prev = 0;
$(document).ready(function() {
$('.button-modal').each(function() {
counter++;
prev = counter - step;
$(this).on('click', function() {
$('.window-'+prev).modal('hide');
$('.window-'+counter).modal('show');
};
});
});
</script>
Give the buttons the same class like 'button-modal'. Then use the class to get the buttons and for each of them add a click listener to hide your previous modal and show your next modal.

Related

html Dynamic table edit button on click event does not load the modal

my end objective is to edit the json data and post back to the server if there is any update on the row
I am using the following code to get the json data to the table and add an edit button at the end column dynamically.
$.getJSON("echo_int_ip.php", function get_mem_update(json) {
my_json = json;
var tr;
var n=5;
for (var i = 0; i < n; i++) {
tr = $('<tr/>');
var mem_date = "<td style=\"min-width:90px\"><label id='mem_date'>" + my_json[i].id + "</label></td>";
tr.append(mem_date);
var mem_name = "<td class=\"contact_name\" style=\"min-width:150px\"><label id='mem_name'>" + my_json[i].fi_name + "</label></td>";
tr.append(mem_name);
var mem_reason = "<td><label id='mem_reason'>" + my_json[i].agent_ + "</label></td>";
tr.append(mem_reason);
var mem_comment = "<td style=\"max-width:150px\"><label id='mem_comment'>" + my_json[i].date + "</label></td>";
tr.append(mem_comment);
var mem_butn = "<td><input type=\"button\" id=\"btnedt\" value=\"Edit\" /></td>";
tr.append(mem_butn);
$('#table_member').append(tr);
}
});
according to the solution provided here, i have used the the following script to create an onclick event and get row data.
<script>
$(document).ready(function () {
$(document).on('click', '#btnedt', function() {
// alert($(this).closest('tr').find('.contact_name').text());
$("#newModal").modal("show");
});
});
</script>
this is a sample modal i am currently trying to load but it does not work. i have spent hours trying figure out a way, but ended up asking from you experts. Thank you in advance
<div class="modal fade" id="newModal" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Error</h4>
</div>
<div class="modal-body">
<p> </p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
First of all you can't have many id's with the same value in a one html page. Cause it will result an error in the future while your doing a lot of code to it. Please change your btnedt to a class not an id. then change your script like this.
<script>
$(document).ready(function () {
$(document).on('click', '.btnedt', function() {
// alert($(this).closest('tr').find('.contact_name').text());
$("#newModal").modal("show");
});
});
</script>
if modal is already the issue. Then here some reason's why its not appearing
Remove the fade class in your modal.
The versions of your Javascript and Bootstrap does not match.
You forgot to include bootstrap.js library in the document
please check this out enter link description here
Use class instead of multiple IDs
Share your modal code
var mem_butn = "<td><input type=\"button\" class=\"btnedt\" value=\"Edit\" /></td>";
<script>
$(document).ready(function () {
$('body').on('click', '.btnedt', function() {
$("#newModal").modal("show");
});
});
</script>

Autofocus back to old box after modal is closed

I apologize if this is a duplicate, but I can't find anything on it.
I am very new to Javascript and am still trying to understand event listeners and how code runs.
Aside from that, I have a bootstrap modal window that pops up when a number is put in an input box and posted.
There is an autofocus on that input box before the modal pops up.
I found help here on how to put the autofocus on a button on the modal window, and it works perfectly fine, as so:
$('.modal').on('shown.bs.modal', function() {
$(this).find('[autofocus]').focus();
});
My problem is when that modal window is closed, I can't get the autofocus back to the input box.
I have tried various versions, these two being my main ideas:
$("#no").click(function() {
$(this).find('[autofocus]').focus();
});
$("#no").click(function() {
$("staffID").focus();
});
Where staffID is the id of the input box.
But it doesn't put the focus back on the input box. The #no id is an id on the modal, so if you press no, you want the original site back with focus on the input.
Can someone point me in the right direction?
Was asked for the HTML as well, here it is (ignore the Icelandic words):
<!--CLOCKIN INPUT FORM-->
<form id="staffIdForm" method="post" action="" class="clockin-form">
<input id="staffID" type="text" name="starfsmannanumer" class="clockin-box" placeholder="Starfsmannanúmer" autofocus/>
<button id="clockIn" type="button" class="btn btn-success">Stimpla</button>
</form>
<!-- WELCOME MODAL -->
<div class="modal fade" id="welcome-modal" role="dialog" aria-labelledby="welcomeModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="welcomeModalLabel">
Góðan daginn <span id="nafn"></span>
</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Innstimplun skráð <span id="time"></span> þann <span id="date"></span></p>
<p>Viltu skrá þig í hádegismat?</p>
</div>
<div class="modal-footer">
<button id="no" type="button" class="btn btn-secondary" data-dismiss="modal" autofocus>Nei</button>
<button id="yes" type="button" class="btn btn-success">Já</button>
</div>
</div>
</div>
</div>
The following javascript needed to run the problem:
$("#clockIn").off('click').on('click', function () {
$("#staffIdForm").submit();
});
$(function getEmployee() {
$("#staffIdForm").on('submit', function(e) {
var staffId = (document.getElementById("staffID").value);
console.log(staffId);
$.post("Attendance/Home/ClockIn", { starfsmannanumer: staffId }, function(data, status) {
console.log(data);
$("#nafn").text(data.name);
$("#clock-out-nafn").text(data.name);
$(function () {
//Display time in message
var dt = new Date();
document.getElementById("time").innerHTML = dt.toLocaleTimeString('en-GB');
document.getElementById("clock-out-time").innerHTML = dt.toLocaleTimeString('en-GB');
//Date message with Icelandic names
var monthNames = [
"janúar", "febrúar", "mars", "apríl", "maí", "júní",
"júlí", "ágúst", "september", "október", "nóvember", "desember"]
var day = dt.getDate();
var monthIndex = dt.getMonth();
document.getElementById("date").innerHTML = day + ". " + monthNames[monthIndex];;
document.getElementById("clock-out-date").innerHTML = day + ". " + monthNames[monthIndex];;
//Either check in or out message or error
if (data.userId == "-1") {
$("#invalid-staff-id").fadeIn('slow', function () {
$("#invalid-staff-id").delay(2000).fadeOut();
});
}
else if (data.timeIn != null && data.timeOut == null) {
$("#welcome-modal").stop(true).modal('show');
}
else if (data.timeIn != null && data.timeOut != null) {
$("#clock-out-message").fadeIn('slow', function() {
$("#clock-out-message").delay(5000).fadeOut();
//TODO: L�ta �tstimplunarskilabo� hverfa ef �tt er � takka
//TODO: Autofocus � 'Nei' takkann
});
}
})
document.getElementById("staffID").value = "";
});
e.preventDefault();
});
});
$('#welcome-modal').on('shown.bs.modal', function () {
$(this).find('[autofocus]').focus();
});
$('#welcome-modal').on('hidden.bs.modal', function () {
$("staffID").focus();
});
I think that is all that is needed.
Bind input focus on modal close. Working solution will be:
$('#myModal').on('hidden.bs.modal', function () {
$('#myInput').focus();
});
Also take a note, that here:
$("#no").click(function() {
$(this).find('[autofocus]').focus();
});
this - is the element you clicked on - seems to be not correct try to find some other DOM element inside of it

Trigger Lazy Load function when modal opens

I am using a lazy load function that works on all my images except those inside modals.
I need to trigger the unveiling when a Bootstrap modal with the class .modal_image_container is opened.
I am trying to incorporate the lazyload function into the show.bs.modal event. Currently it only unveils the image on the first modal clicked.
lazy load function (not my code)
(function($) {
$.fn.unveil = function(threshold, callback) {
var $w = $(window),
th = threshold || 0,
retina = window.devicePixelRatio > 1,
attrib = retina? "data-src-retina" : "data-src",
images = this,
loaded;
this.one("unveil", function() {
var source = this.getAttribute(attrib);
source = source || this.getAttribute("data-src");
if (source) {
this.setAttribute("src", source);
if (typeof callback === "function") callback.call(this);
}
});
function unveil() {
var inview = images.filter(function() {
var $e = $(this);
if ($e.is(":hidden")) return;
var wt = $w.scrollTop(),
wb = wt + $w.height(),
et = $e.offset().top,
eb = et + $e.height();
return eb >= wt - th && et <= wb + th;
});
loaded = inview.trigger("unveil");
images = images.not(loaded);
}
$w.on("scroll.unveil resize.unveil lookup.unveil", unveil);
unveil();
return this;
};
})(window.jQuery || window.Zepto);
calling the lazy load function
$(document).ready(function lazyload() {
$("img.lazy").unveil(300, function() {
$(this).load(function() {
this.style.opacity = 1;
});
});
});
My attempt at adapting it to fire on modal open
$('[data-toggle="modal"]').on('show.bs.modal', function() {
$("img.lazy").unveil(0,function() {
console.log('test 1');
$(this).load(function() {
this.style.opacity = 1;
});
});
});
One of three of the modals, same class names, diff id's (obviously).
<!-- MODAL Image Item 1 Pic 1 -->
<div id="140image" class="modal product_images_modal fade" role="dialog" tabindex="-1">
<div class="modal-dialog modal-lg modal_image_container">
<div class="modal-content">
<!-- Modal Header-->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">Close</span></button>
</div>
<!-- Product Modal Body -->
<div class="modal-body" data-dismiss="modal">
<h2 class="modal-title heading">Title</h2>
<img class="product_image_modal center-block lazy" src="/assets/images/products/blank_625.gif" data-src="/assets/images/products/140_900.jpg" alt="Large image of 140 litre Polypropylene Soakwell">
</div>
<!-- Modal Footer-->
<div class="modal-footer">
<button type="button" class="btn btn-default close" aria-label="Close" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
and finally the trigger that opens the modal on click
<!-- item image -->
<img class="product_image lazy" data-toggle="modal" data-target="#140image" src="/assets/images/products/200.gif " alt="Geofabric" data-src="assets/images/products/600.jpg">
Can anyone assist in pointing me in the right direction? Thanks.
try this one
$('.modal_image_container').on('shown.bs.modal', function() {
$(this).find("img.lazy").unveil(0, function() {
console.log('test 1');
$(this).load(function() {
this.style.opacity = 1;
});
});
});

jQuery loop through set of divs, one at a time

I am building a wordpress onboarding plugin.
I have an array that contains the content for each step of onboarding process, then a function that outputs each step in it's own container, with it's own class:
static function action_build_steps() {
$items = Onboarding_Dashboard::dashboard_onboarding_content();
$output = '';
foreach ($items as $step => $item) {
// Classes
$step_class = array();
$step_class[] = str_replace("-", "", $step);
$step_class[] = (isset($item['class']) ? $item['class'] : NULL);
$step_class = implode( ' ', $step_class );
echo '<div id="onboarding_steps_container" class="'.$step_class.' onboarding-'.Onboarding_Setup::onboarding_slug().'" style="left:'.$item['left'].'; top:'.$item['top'].'; width:'.$item['width'].';">';
echo '<div class="onboarding_steps">';
echo '<h2>'.$item['title'].'</h2>';
echo '<p>'.$item['content'].'</p>';
if(isset($item['css_arrow'])) {
echo '<div class="arrow_'.$item['css_arrow'].'"></div>';
}
echo '</div>';
echo '<div class="button_holder">';
if (($item['show-prev'])=='true') {
echo '<button id="prev" class="'.$step_class.'"><i class="fa fa-chevron-left"></i> PREV</button>';
}
if(($item['show-next'])=='true') {
echo '<button onboarding_stage="dashboard" id="next" class="'.$step_class.'">NEXT <i class="fa fa-chevron-right"></i></button>';
}
echo '</div>';
echo '</div>';
}
return $output;
}
This results in showing ALL steps at once, however, the plan is to show one step at a time, and when the user clicks "Next" or "Prev" they see the next or previous step.
I know I need to do this using jQuery but can't think how I will do it, mainly because I have a dynamic number of steps - it's not a set number.
So far, I have just hidden all steps using this script:
jQuery(function($) {
$('.onboarding-<?php echo Onboarding_Setup::onboarding_slug(); ?>').hide();
});
My outputted html looks a bit like this (I'll take out the content)
<div id="onboarding_steps_container" class="step1 onboarding-dashboard" style="left:50%; top:320px; width:500px;">
<div class="button_holder">
<button onboarding_stage="dashboard" id="prev" class="step1 ">NEXT <i class="fa fa-chevron-right"></i></button>
<button onboarding_stage="dashboard" id="next" class="step1 ">NEXT <i class="fa fa-chevron-right"></i></button>
</div>
</div>
<div id="onboarding_steps_container" class="step2 onboarding-dashboard" style="left:50%; top:320px; width:500px;">
<div class="button_holder">
<button onboarding_stage="dashboard" id="prev" class="step2 ">NEXT <i class="fa fa-chevron-right"></i></button>
<button onboarding_stage="dashboard" id="next" class="step2 ">NEXT <i class="fa fa-chevron-right"></i></button>
</div>
</div>
Where you see the word 'dashboard' in the script above, that is also dynamically added depending on the page the user is on. Also, the first step doesn't have a previous button, and the last step doesn't have a next button (they do in my code above, but just for demonstration)
How would I iterate through each step, 1 at a time, hideing the previous step, then showing the next?
UPDATE:
Here is what I've managed to come up with so far:
jQuery(function($) {
var index = 0;
$(function() {
$('.onboarding_steps_container:not(:first)').hide();
$('#next').click(function() {
if (($('.onboarding_steps_container').length - 1) >= index) {
$('.onboarding_steps_container:eq(' + index + ')').hide();
index++;
$('.onboarding_steps_container:eq(' + index + ')').show();
}
});
$('#prev').click(function() {
if (index != 0) {
$('.onboarding_steps_container:eq(' + index + ')').hide();
index--;
$('.onboarding_steps_container:eq(' + index + ')').show();
}
});
});
I think my issue is that each step has a different button (even though the ID is the same a referenced in my script)
});
However, this only works for the first button click, no others
Here's a JSFiddle showing my situation:
https://jsfiddle.net/fwysy2rr/
Make a function in javascript call onclick on next btn
var current_div =1;
function showDiv(var i){
//first hide all div having class onboarding-
//show next div
$(".step"+current_div+1 + "onboarding-dashboard");
//set current div
current_div +=1 ;
}

Multiple modals overlay

I need that the overlay shows above the first modal, not in the back.
$('#openBtn').click(function(){
$('#myModal').modal({show:true})
});
<a data-toggle="modal" href="#myModal" class="btn btn-primary">Launch modal</a>
<div class="modal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal title</h4>
</div><div class="container"></div>
<div class="modal-body">
Content for the dialog / modal goes here.
<br>
<br>
<br>
<br>
<br>
<a data-toggle="modal" href="#myModal2" class="btn btn-primary">Launch modal</a>
</div>
<div class="modal-footer">
Close
Save changes
</div>
</div>
</div>
</div>
<div class="modal" id="myModal2" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Second Modal title</h4>
</div><div class="container"></div>
<div class="modal-body">
Content for the dialog / modal goes here.
</div>
<div class="modal-footer">
Close
Save changes
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/js/bootstrap.min.js"></script>
I tried to change the z-index of .modal-backdrop, but it becomes a mess.
In some cases I have more than two modals on the same page.
Solution inspired by the answers of #YermoLamers & #Ketwaroo.
Backdrop z-index fix
This solution uses a setTimeout because the .modal-backdrop isn't created when the event show.bs.modal is triggered.
$(document).on('show.bs.modal', '.modal', function() {
const zIndex = 1040 + 10 * $('.modal:visible').length;
$(this).css('z-index', zIndex);
setTimeout(() => $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack'));
});
This works for every .modal created on the page (even dynamic modals)
The backdrop instantly overlays the previous modal
Example jsfiddle
z-index
If you don't like the hardcoded z-index for any reason you can calculate the highest z-index on the page like this:
const zIndex = 10 +
Math.max(...Array.from(document.querySelectorAll('*')).map((el) => +el.style.zIndex));
Scrollbar fix
If you have a modal on your page that exceeds the browser height, then you can't scroll in it when closing an second modal. To fix this add:
$(document).on('hidden.bs.modal', '.modal',
() => $('.modal:visible').length && $(document.body).addClass('modal-open'));
Versions
This solution is tested with bootstrap 3.1.0 - 3.3.5
I realize an answer has been accepted, but I strongly suggest not hacking bootstrap to fix this.
You can pretty easily achieve the same effect by hooking the shown.bs.modal and hidden.bs.modal event handlers and adjusting the z-index there.
Here's a working example
A bit more info is available here.
This solution works automatically with arbitrarily deeply stacks modals.
The script source code:
$(document).ready(function() {
$('.modal').on('hidden.bs.modal', function(event) {
$(this).removeClass( 'fv-modal-stack' );
$('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) - 1 );
});
$('.modal').on('shown.bs.modal', function (event) {
// keep track of the number of open modals
if ( typeof( $('body').data( 'fv_open_modals' ) ) == 'undefined' ) {
$('body').data( 'fv_open_modals', 0 );
}
// if the z-index of this modal has been set, ignore.
if ($(this).hasClass('fv-modal-stack')) {
return;
}
$(this).addClass('fv-modal-stack');
$('body').data('fv_open_modals', $('body').data('fv_open_modals' ) + 1 );
$(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals' )));
$('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals')));
$('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack');
});
});
Combining A1rPun's answer with the suggestion by StriplingWarrior, I came up with this:
$(document).on({
'show.bs.modal': function () {
var zIndex = 1040 + (10 * $('.modal:visible').length);
$(this).css('z-index', zIndex);
setTimeout(function() {
$('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
}, 0);
},
'hidden.bs.modal': function() {
if ($('.modal:visible').length > 0) {
// restore the modal-open class to the body element, so that scrolling works
// properly after de-stacking a modal.
setTimeout(function() {
$(document.body).addClass('modal-open');
}, 0);
}
}
}, '.modal');
Works even for dynamic modals added after the fact, and removes the second-scrollbar issue. The most notable thing that I found this useful for was integrating forms inside modals with validation feedback from Bootbox alerts, since those use dynamic modals and thus require you to bind the event to document rather than to .modal, since that only attaches it to existing modals.
Fiddle here.
Something shorter version based off Yermo Lamers' suggestion, this seems to work alright. Even with basic animations like fade in/out and even crazy batman newspaper rotate. http://jsfiddle.net/ketwaroo/mXy3E/
$('.modal').on('show.bs.modal', function(event) {
var idx = $('.modal:visible').length;
$(this).css('z-index', 1040 + (10 * idx));
});
$('.modal').on('shown.bs.modal', function(event) {
var idx = ($('.modal:visible').length) -1; // raise backdrop after animation.
$('.modal-backdrop').not('.stacked').css('z-index', 1039 + (10 * idx));
$('.modal-backdrop').not('.stacked').addClass('stacked');
});
A simple solution for Bootstrap 4.5
.modal.fade {
background: rgba(0, 0, 0, 0.5);
}
.modal-backdrop.fade {
opacity: 0;
}
I created a Bootstrap plugin that incorporates a lot of the ideas posted here.
Demo on Bootply: http://www.bootply.com/cObcYInvpq
Github: https://github.com/jhaygt/bootstrap-multimodal
It also addresses the issue with successive modals causing the backdrop to become darker and darker. This ensures that only one backdrop is visible at any given time:
if(modalIndex > 0)
$('.modal-backdrop').not(':first').addClass('hidden');
The z-index of the visible backdrop is updated on both the show.bs.modal and hidden.bs.modal events:
$('.modal-backdrop:first').css('z-index', MultiModal.BASE_ZINDEX + (modalIndex * 20));
When solving Stacking modals scrolls the main page when one is closed i found that newer versions of Bootstrap (at least since version 3.0.3) do not require any additional code to stack modals.
You can add more than one modal (of course having a different ID) to your page. The only issue found when opening more than one modal will be that closing one remove the modal-open class for the body selector.
You can use the following Javascript code to re-add the modal-open :
$('.modal').on('hidden.bs.modal', function (e) {
if($('.modal').hasClass('in')) {
$('body').addClass('modal-open');
}
});
In the case that do not need the backdrop effect for the stacked modal you can set data-backdrop="false".
Version 3.1.1. fixed Fix modal backdrop overlaying the modal's scrollbar, but the above solution seems also to work with earlier versions.
If you're looking for Bootstrap 4 solution, there's an easy one using pure CSS:
.modal.fade {
background: rgba(0,0,0,0.5);
}
Finally solved. I tested it in many ways and works fine.
Here is the solution for anyone that have the same problem:
Change the Modal.prototype.show function (at bootstrap.js or modal.js)
FROM:
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element
.addClass('in')
.attr('aria-hidden', false)
that.enforceFocus()
TO:
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$backdrop
.css("z-index", (1030 + (10 * $(".modal.fade.in").length)))
that.$element
.css("z-index", (1040 + (10 * $(".modal.fade.in").length)))
.addClass('in')
.attr('aria-hidden', false)
that.enforceFocus()
It's the best way that i found: check how many modals are opened and change the z-index of the modal and the backdrop to a higher value.
Try adding the following to your JS on bootply
$('#myModal2').on('show.bs.modal', function () {
$('#myModal').css('z-index', 1030); })
$('#myModal2').on('hidden.bs.modal', function () {
$('#myModal').css('z-index', 1040); })
Explanation:
After playing around with the attributes(using Chrome's dev tool), I have realized that any z-index value below 1031 will put things behind the backdrop.
So by using bootstrap's modal event handles I set the z-index to 1030. If #myModal2 is shown and set the z-index back to 1040 if #myModal2 is hidden.
Demo
My solution for bootstrap 4, working with unlimited depth of modals and dynamic modal.
$('.modal').on('show.bs.modal', function () {
var $modal = $(this);
var baseZIndex = 1050;
var modalZIndex = baseZIndex + ($('.modal.show').length * 20);
var backdropZIndex = modalZIndex - 10;
$modal.css('z-index', modalZIndex).css('overflow', 'auto');
$('.modal-backdrop.show:last').css('z-index', backdropZIndex);
});
$('.modal').on('shown.bs.modal', function () {
var baseBackdropZIndex = 1040;
$('.modal-backdrop.show').each(function (i) {
$(this).css('z-index', baseBackdropZIndex + (i * 20));
});
});
$('.modal').on('hide.bs.modal', function () {
var $modal = $(this);
$modal.css('z-index', '');
});
A1rPun's answer works perfectly after a minor modification (Bootstrap 4.6.0). My reputation won't let me comment, so I'll post an answer.
I just replaced every .modal:visible for .modal.show.
So, to fix the backdrop when opening multiple modals:
$(document).on('show.bs.modal', '.modal', function () {
var zIndex = 1040 + (10 * $('.modal.show').length);
$(this).css('z-index', zIndex);
setTimeout(function() {
$('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
}, 0);
});
And, to fix the scrollbar:
$(document).on('hidden.bs.modal', '.modal', function () {
$('.modal.show').length && $(document.body).addClass('modal-open');
});
The solution to this for me was to NOT use the "fade" class on my modal divs.
Note: all answers are "hacks" since Bootstrap doesn't officially support multiple modals..
"Bootstrap only supports one modal window at a time. Nested modals
aren’t supported as we believe them to be poor user experiences."
Here are some CSS workarounds/hacks...
Bootstrap 5.2 (Update 2023)
This version has changed a little because Bootstrap now auto hides any other open modals when a new one is opened. Therefore, z-index CSS won't work. However, with a little JS you can force the first modal to stay open by reshowing it when the 2nd one is shown... (Again, this is a hack as Bootstrap does not support multiple open modals)
const myModal = bootstrap.Modal.getOrCreateInstance('#myModal')
const myModal2El = document.getElementById('myModal2')
// when 2nd modal is shown, reshow 1st modal
myModal2El.addEventListener('show.bs.modal', event => {
// force re-show of modal 1
myModal.show()
})
https://codeply.com/p/mYhmJ2fNau
Bootstrap 5 beta (Update 2021)
The default z-index for modals has changed again to 1060. Therefore, to override the modals and backdrop use..
.modal:nth-of-type(even) {
z-index: 1062 !important;
}
.modal-backdrop.show:nth-of-type(even) {
z-index: 1061 !important;
}
https://codeply.com/p/yNgonlFihM
The z-index for modals in Bootstrap 4 has changed again to 1050. Therefore, to override the open modals and backdrop use.
Bootstrap 4.x (Update 2018)
.modal:nth-of-type(even) {
z-index: 1052 !important;
}
.modal-backdrop.show:nth-of-type(even) {
z-index: 1051 !important;
}
https://codeply.com/p/29sH0ofTZb
Bootstrap 3.x (Original Answer)
Here is some CSS using nth-of-type selectors that seems to work:
.modal:nth-of-type(even) {
z-index: 1042 !important;
}
.modal-backdrop.in:nth-of-type(even) {
z-index: 1041 !important;
}
https://codeply.com/p/w8yjOM4DFb
Everytime you run sys.showModal function increment z-index and set it to your new modal.
function system() {
this.modalIndex = 2000;
this.showModal = function (selector) {
this.modalIndex++;
$(selector).modal({
backdrop: 'static',
keyboard: true
});
$(selector).modal('show');
$(selector).css('z-index', this.modalIndex );
}
}
var sys = new system();
sys.showModal('#myModal1');
sys.showModal('#myModal2');
No script solutions , using only css given you have two layers of modals, set the 2nd modal to a higher z index
.second-modal { z-index: 1070 }
div.modal-backdrop + div.modal-backdrop {
z-index: 1060;
}
If you want a specific modal to appear on top of another open modal, try adding the HTML of the topmost modal after the other modal div.
This worked for me:
<div id="modal-under" class="modal fade" ... />
<!--
This modal-upper should appear on top of #modal-under when both are open.
Place its HTML after #modal-under. -->
<div id="modal-upper" class="modal fade" ... />
Based on the example fiddle of this answer, I updated it to support bootstrap 3 and 4 and fix all issues mentioned at the comments there. As i noticed them also, because i have some modals that have a timeout and close automatically.
It will not work with bootstrap 5. Bootstrap 5 doesn't store the bs.modal object anymore using node.data('bs.modal').
I suggest, viewing the snippet in full screen.
Bootstrap 3 using the same example as the answer mentiond, except that dialog 4 is modified.
!function () {
var z = "bs.modal.z-index.base",
re_sort = function (el) {
Array.prototype.slice.call($('.modal.show,.modal.in').not(el))
.sort(function (a, b) { // sort by z-index lowest to highest
return +a.style.zIndex - +b.style.zIndex
})
.forEach(function (el, idx) { // re-set the z-index based on the idx
el.style.zIndex = $(el).data(z) + (2 * idx);
const b = $(el).data('bs.modal')._backdrop || $(el).data("bs.modal").$backdrop;
if (b) {
$(b).css("z-index", +el.style.zIndex - 1);
}
});
};
$(document).on('show.bs.modal', '.modal', function (e) {
// removing the currently set zIndex if any
this.style.zIndex = '';
/*
* should be 1050 always, if getComputedStyle is not supported use 1032 as variable...
*
* see https://getbootstrap.com/docs/4.0/layout/overview/#z-index and adjust the
* other values to higher ones, if required
*
* Bootstrap 3: https:////netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.css
.modal {
[...]
z-index: 1050;
[...]
}
.modal-backdrop {
[...]
z-index: 1040;
[...]
}
* Bootstrap 4: https://getbootstrap.com/docs/4.0/layout/overview/#z-index
*
*
* lowest value which doesn't interfer with other bootstrap elements
* since we manipulate the z-index of the backdrops too we need two for each modal
* using 1032 you could open up to 13 modals without overlapping popovers
*/
if (!$(this).data(z)) {
let def = +getComputedStyle(this).zIndex; // 1050 by default
def = 1032;
$(this).data(z, def);
}
// resort all others, except this
re_sort(this);
// 2 is fine 1 layer for the modal, 1 layer for the backdrop
var zIndex = $(this).data(z) + (2 * $('.modal.show,.modal.in').not(this).length);
e.target.style.zIndex = zIndex;
/*
* Bootstrap itself stores the var using jQuery data property the backdrop
* is present there, even if it may not be attached to the DOM
*
* If it is not present, wait for it, using requestAnimationFrame loop
*/
const waitForBackdrop = function () {
try { // can fail to get the config if the modal is opened for the first time
const config = $(this).data('bs.modal')._config || $(this).data('bs.modal').options;
if (config.backdrop != false) {
const node = $(this).data('bs.modal')._backdrop ||
$(this).data("bs.modal").$backdrop;
if (node) {
$(node).css('z-index', +this.style.zIndex - 1);
} else {
window.requestAnimationFrame(waitForBackdrop);
}
}
} catch (e) {
window.requestAnimationFrame(waitForBackdrop);
}
}.bind(this);
waitForBackdrop();
});
$(document).on("shown.bs.modal", ".modal", function () {
re_sort();
});
$(document).on('hidden.bs.modal', '.modal', function (event) {
this.style.zIndex = ''; // when hidden, remove the z-index
if (this.isConnected) {
const b = $(this).data('bs.modal')._backdrop || $(this).data("bs.modal").$backdrop;
if (b) {
$(b).css("z-index", '');
}
}
re_sort();
// if still backdrops are present at dom - readd modal-open
if ($('.modal-backdrop.show,.modal-backdrop.in').length)
$(document.body).addClass("modal-open");
})
}();
/* crazy batman newspaper spinny thing */
.rotate {
transform:rotate(180deg);
transition:all 0.25s;
}
.rotate.in {
transform:rotate(1800deg);
transition:all 0.75s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet"/>
<h2>Stacked Bootstrap Modal Example.</h2>
<a data-toggle="modal" href="#myModal" class="btn btn-primary">Launch modal</a>
<div class="modal fade" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal 1</h4>
</div>
<div class="container"></div>
<div class="modal-body">Content for the dialog / modal goes here.
<br>
<br>
<br>
<p>more content</p>
<br>
<br>
<br> <a data-toggle="modal" href="#myModal2" class="btn btn-primary">Launch modal</a>
</div>
<div class="modal-footer"> Close
Save changes
</div>
</div>
</div>
</div>
<div class="modal fade rotate" id="myModal2">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal 2</h4>
</div>
<div class="container"></div>
<div class="modal-body">Content for the dialog / modal goes here.
<br>
<br>
<p>come content</p>
<br>
<br>
<br> <a data-toggle="modal" href="#myModal3" class="btn btn-primary">Launch modal</a>
</div>
<div class="modal-footer"> Close
Save changes
</div>
</div>
</div>
</div>
<div class="modal fade" id="myModal3">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal 3</h4>
</div>
<div class="container"></div>
<div class="modal-body">Content for the dialog / modal goes here.
<br>
<br>
<br>
<br>
<br> <a data-toggle="modal" href="#myModal4" class="btn btn-primary">Launch modal</a>
</div>
<div class="modal-footer"> Close
Save changes
</div>
</div>
</div>
</div>
<div class="modal fade" id="myModal4">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal 4</h4>
</div>
<div class="container"></div>
<div class="modal-body">
<button onclick="$('#myModal').modal('hide');" class="btn btn-primary">hide #1</button>
<button onclick="$('#myModal').modal('show');" class="btn btn-primary">show #1</button>
<br>
<button onclick="$('#myModal2').modal('hide');" class="btn btn-primary">hide #2</button>
<button onclick="$('#myModal2').modal('show');" class="btn btn-primary">show #2</button>
<br>
<button onclick="$('#myModal3').modal('hide');" class="btn btn-primary">hide #3</button>
<button onclick="$('#myModal3').modal('show');" class="btn btn-primary">show #3</button>
</div>
<div class="modal-footer"> Close
Save changes
</div>
</div>
</div>
</div>
Bootstrap 4 (see Bootstrap 3 snippet for commented code)
!function () {
var z = "bs.modal.z-index.base",
re_sort = function (el) {
Array.prototype.slice.call($('.modal.show,.modal.in').not(el))
.sort(function (a, b) {
return +a.style.zIndex - +b.style.zIndex
})
.forEach(function (el, idx) {
el.style.zIndex = $(el).data(z) + (2 * idx);
const b = $(el).data('bs.modal')._backdrop || $(el).data("bs.modal").$backdrop;
if (b) {
$(b).css("z-index", +el.style.zIndex - 1);
}
});
};
$(document).on('show.bs.modal', '.modal', function (e) {
this.style.zIndex = '';
if (!$(this).data(z)) {
let def = +getComputedStyle(this).zIndex;
def = 1032;
$(this).data(z, def);
}
re_sort(this);
var zIndex = $(this).data(z) + (2 * $('.modal.show,.modal.in').not(this).length);
e.target.style.zIndex = zIndex;
const waitForBackdrop = function () {
try {
const config = $(this).data('bs.modal')._config || $(this).data('bs.modal').options;
if (config.backdrop != false) {
const node = $(this).data('bs.modal')._backdrop ||
$(this).data("bs.modal").$backdrop;
if (node) {
$(node).css('z-index', +this.style.zIndex - 1);
} else {
window.requestAnimationFrame(waitForBackdrop);
}
}
} catch (e) {
window.requestAnimationFrame(waitForBackdrop);
}
}.bind(this);
waitForBackdrop();
});
$(document).on("shown.bs.modal", ".modal", function () {
re_sort();
});
$(document).on('hidden.bs.modal', '.modal', function (event) {
this.style.zIndex = '';
if (this.isConnected) {
const b = $(this).data('bs.modal')._backdrop || $(this).data("bs.modal").$backdrop;
if (b) {
$(b).css("z-index", '');
}
}
re_sort();
if ($('.modal-backdrop.show,.modal-backdrop.in').length)
$(document.body).addClass("modal-open");
})
}();
// creates dynamic modals i used this for stuff like
// `enterSomething('stuff','to','display').then(...)`
!function() {
let a = (i, a) => Array.prototype.forEach.call(a, (e) => $('#' + i + '-modal').find('.modal-body').append(e)),
b = function () { $(this).remove() },
c = (i, a) => Array.prototype.forEach.call(a, (e) => $('#' + i + '-modal-text-container').append(e)),
r = () => 'dialog-' + (Date.now() + '-' + Math.random()).replace('.', '-');
this.createModal = function createModal() {
let id = r();
$(document.body).append('<div class="modal fade" tabindex="-1" role="dialog" data-backdrop="static" aria-hidden="true" id="' + id + '-modal"><div class="modal-dialog d-flex modal-xl"><div class="modal-content align-self-stretch" style="overflow: hidden; max-height: -webkit-fill-available;"><div class="modal-header py-1"><h5 class="modal-header-text p-0 m-0"></h5><button id="' + id + '-modal-btn-close" type="button" tabindex="-1" class="close" data-dismiss="modal" aria-label="Close" title="Close"><span aria-hidden="true">×</span></button></div><div class="modal-body py-2"></div><div class="modal-footer py-1"><button type="button" class="btn btn-primary btn-sm" id="' + id + '-modal-btn-ok">Okay</button></div></div></div></div>');
$('#' + id + '-modal-btn-ok').on('click', () => $('#' + id + '-modal').modal('hide'));
$('#' + id + '-modal').on('shown.bs.modal', () => $('#' + id + '-modal-btn-ok').focus()).on('hidden.bs.modal', b).modal('show');
$('#' + id + '-modal').find(".modal-header-text").html("Title");
a(id, arguments);
return new Promise((r) => $('#' + id + '-modal').on('hide.bs.modal', () => r()));
}
}();
function another() {
createModal(
$("<button class='btn mx-1'>Another...</button>").on("click", another),
$("<button class='btn mx-1'>Close lowest</button>").on("click", closeLowest),
$("<button class='btn mx-1'>Bring lowest to front</button>").on("click", lowestToFront),
$("<p>").text($(".modal.show,.modal.in").length)
).then(() => console.log("modal closed"));
// only for this example:
$(".modal").last().css('padding-top', ($(".modal.show,.modal.in").length * 20) +'px');
}
function closeLowest() {
$(Array.prototype.slice.call($('.modal.show,.modal.in'))
.sort(function (a, b) { // sort by z-index lowest to highest
return +a.style.zIndex - +b.style.zIndex
})).first().modal('hide');
}
function lowestToFront() {
$(Array.prototype.slice.call($('.modal.show,.modal.in'))
.sort(function (a, b) { // sort by z-index lowest to highest
return +a.style.zIndex - +b.style.zIndex
})).first().trigger('show.bs.modal');
}
another();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<p>Use inspecter to check z-index values</p>
<button class="btn btn-outline-primary" onclick="another()">Click!</button>
Solution for Bootstrap 5 (pure JS).
Solution inspired by the answers of #A1rPun.
// On modal open
document.addEventListener('show.bs.modal', function(e) {
// Get count of opened modals
let modalsCount = 1;
document.querySelectorAll('.modal').forEach(function(modalElement) {
if (modalElement.style.display == 'block') {
modalsCount++;
}
});
// Set modal and backdrop z-indexes
const zIndex = 1055 + 10 * modalsCount;
e.target.style.zIndex = zIndex;
setTimeout(() => {
const backdropNotStacked = document.querySelector('.modal-backdrop:not(.modal-stack)');
backdropNotStacked.style.zIndex = ('z-index', zIndex - 5);
backdropNotStacked.classList.add('modal-stack');
});
});
Explanation
loop all visible modals (you cannot use the pseudoselector :visible, which is only in jquery)
calculate new z-index. Default for Bootstrap 5 is 1055, so:
default(1055) + 10 * number of opened modals
set this new calculated z-index to the modal
identify backdrop (backdrop without specified class - in our case .modal-stack)
set this new calculated z-index -5 to the backdrop
add class .modal-stack to the backdrop to prevent getting this backdrop while opening next modal
Each modal should be given a different id and each link should be targeted to a different modal id. So it should be something like that:
<a href="#myModal" data-toggle="modal">
...
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"></div>
...
<a href="#myModal2" data-toggle="modal">
...
<div id="myModal2" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"></div>
...
EDIT: Bootstrap 3.3.4 has solved this problem (and other modal issues) so if you can update your bootstrap CSS and JS that would be the best solution. If you can't update the solution below will still work and essentially does the same thing as bootstrap 3.3.4 (recalculate and apply padding).
As Bass Jobsen pointed out, newer versions of Bootstrap have the z-index solved. The modal-open class and padding-right were still problems for me but this scripts inspired by Yermo Lamers solution solves it. Just drop it in your JS file and enjoy.
$(document).on('hide.bs.modal', '.modal', function (event) {
var padding_right = 0;
$.each($('.modal'), function(){
if($(this).hasClass('in') && $(this).modal().data('bs.modal').scrollbarWidth > padding_right) {
padding_right = $(this).modal().data('bs.modal').scrollbarWidth
}
});
$('body').data('padding_right', padding_right + 'px');
});
$(document).on('hidden.bs.modal', '.modal', function (event) {
$('body').data('open_modals', $('body').data('open_modals') - 1);
if($('body').data('open_modals') > 0) {
$('body').addClass('modal-open');
$('body').css('padding-right', $('body').data('padding_right'));
}
});
$(document).on('shown.bs.modal', '.modal', function (event) {
if (typeof($('body').data('open_modals')) == 'undefined') {
$('body').data('open_modals', 0);
}
$('body').data('open_modals', $('body').data('open_modals') + 1);
$('body').css('padding-right', (parseInt($('body').css('padding-right')) / $('body').data('open_modals') + 'px'));
});
Check this out! This solution solved the problem for me, few simple CSS lines:
.modal:nth-of-type(even) {
z-index: 1042 !important;
}
.modal-backdrop.in:nth-of-type(even) {
z-index: 1041 !important;
}
Here is a link to where I found it: Bootply
Just make sure that the .modual that need to appear on Top is second in HTML code, so CSS can find it as "even".
work for open/close multi modals
jQuery(function()
{
jQuery(document).on('show.bs.modal', '.modal', function()
{
var maxZ = parseInt(jQuery('.modal-backdrop').css('z-index')) || 1040;
jQuery('.modal:visible').each(function()
{
maxZ = Math.max(parseInt(jQuery(this).css('z-index')), maxZ);
});
jQuery('.modal-backdrop').css('z-index', maxZ);
jQuery(this).css("z-index", maxZ + 1);
jQuery('.modal-dialog', this).css("z-index", maxZ + 2);
});
jQuery(document).on('hidden.bs.modal', '.modal', function ()
{
if (jQuery('.modal:visible').length)
{
jQuery(document.body).addClass('modal-open');
var maxZ = 1040;
jQuery('.modal:visible').each(function()
{
maxZ = Math.max(parseInt(jQuery(this).css('z-index')), maxZ);
});
jQuery('.modal-backdrop').css('z-index', maxZ-1);
}
});
});
Demo
https://www.bootply.com/cObcYInvpq#
For me, these simple scss rules worked perfectly:
.modal.show{
z-index: 1041;
~ .modal.show{
z-index: 1043;
}
}
.modal-backdrop.show {
z-index: 1040;
+ .modal-backdrop.show{
z-index: 1042;
}
}
If these rules cause the wrong modal to be on top in your case, either change the order of your modal divs, or change (odd) to (even) in above scss.
I had a similar scenario, and after a little bit of R&D I found a solution. Although I'm not great in JS still I have managed to write down a small query.
http://jsfiddle.net/Sherbrow/ThLYb/
<div class="ingredient-item" data-toggle="modal" data-target="#myModal">test1 <p>trerefefef</p></div>
<div class="ingredient-item" data-toggle="modal" data-target="#myModal">tst2 <p>Lorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem Ipsum</p></div>
<div class="ingredient-item" data-toggle="modal" data-target="#myModal">test3 <p>afsasfafafsa</p></div>
<!-- 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">×</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
...
</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>
</div>
</div>
$('.ingredient-item').on('click', function(e){
e.preventDefault();
var content = $(this).find('p').text();
$('.modal-body').html(content);
});
Add global variable in modal.js
var modalBGIndex = 1040; // modal backdrop background
var modalConIndex = 1042; // modal container data
// show function inside add variable - Modal.prototype.backdrop
var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
modalConIndex = modalConIndex + 2; // add this line inside "Modal.prototype.show"
that.$element
.show()
.scrollTop(0)
that.$element.css('z-index',modalConIndex) // add this line after show modal
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
modalBGIndex = modalBGIndex + 2; // add this line increase modal background index 2+
this.$backdrop.addClass('in')
this.$backdrop.css('z-index',modalBGIndex) // add this line after backdrop addclass
The other solutions did not work for me out of the box. I think perhaps because I am using a more recent version of Bootstrap (3.3.2).... the overlay was appearing on top of the modal dialog.
I refactored the code a bit and commented out the part that was adjusting the modal-backdrop. This fixed the issue.
var $body = $('body');
var OPEN_MODALS_COUNT = 'fv_open_modals';
var Z_ADJUSTED = 'fv-modal-stack';
var defaultBootstrapModalZindex = 1040;
// keep track of the number of open modals
if ($body.data(OPEN_MODALS_COUNT) === undefined) {
$body.data(OPEN_MODALS_COUNT, 0);
}
$body.on('show.bs.modal', '.modal', function (event)
{
if (!$(this).hasClass(Z_ADJUSTED)) // only if z-index not already set
{
// Increment count & mark as being adjusted
$body.data(OPEN_MODALS_COUNT, $body.data(OPEN_MODALS_COUNT) + 1);
$(this).addClass(Z_ADJUSTED);
// Set Z-Index
$(this).css('z-index', defaultBootstrapModalZindex + (1 * $body.data(OPEN_MODALS_COUNT)));
//// BackDrop z-index (Doesn't seem to be necessary with Bootstrap 3.3.2 ...)
//$('.modal-backdrop').not( '.' + Z_ADJUSTED )
// .css('z-index', 1039 + (10 * $body.data(OPEN_MODALS_COUNT)))
// .addClass(Z_ADJUSTED);
}
});
$body.on('hidden.bs.modal', '.modal', function (event)
{
// Decrement count & remove adjusted class
$body.data(OPEN_MODALS_COUNT, $body.data(OPEN_MODALS_COUNT) - 1);
$(this).removeClass(Z_ADJUSTED);
// Fix issue with scrollbar being shown when any modal is hidden
if($body.data(OPEN_MODALS_COUNT) > 0)
$body.addClass('modal-open');
});
As a side note, if you want to use this in AngularJs, just put the code inside of your module's .run() method.
In my case the problem was caused by a browser extension that includes the bootstrap.js files where the show event handled twice and two modal-backdrop divs are added, but when closing the modal only one of them is removed.
Found that by adding a subtree modification breakpoint to the body element in chrome, and tracked adding the modal-backdrop divs.
$(window).scroll(function(){
if($('.modal.in').length && !$('body').hasClass('modal-open'))
{
$('body').addClass('modal-open');
}
});
Update: 22.01.2019, 13.41
I optimized the solution by jhay, which also supports closing and opening same or different dialogs when for example stepping from one detail data to another forwards or backwards.
(function ($, window) {
'use strict';
var MultiModal = function (element) {
this.$element = $(element);
this.modalIndex = 0;
};
MultiModal.BASE_ZINDEX = 1040;
/* Max index number. When reached just collate the zIndexes */
MultiModal.MAX_INDEX = 5;
MultiModal.prototype.show = function (target) {
var that = this;
var $target = $(target);
// Bootstrap triggers the show event at the beginning of the show function and before
// the modal backdrop element has been created. The timeout here allows the modal
// show function to complete, after which the modal backdrop will have been created
// and appended to the DOM.
// we only want one backdrop; hide any extras
setTimeout(function () {
/* Count the number of triggered modal dialogs */
that.modalIndex++;
if (that.modalIndex >= MultiModal.MAX_INDEX) {
/* Collate the zIndexes of every open modal dialog according to its order */
that.collateZIndex();
}
/* Modify the zIndex */
$target.css('z-index', MultiModal.BASE_ZINDEX + (that.modalIndex * 20) + 10);
/* we only want one backdrop; hide any extras */
if (that.modalIndex > 1)
$('.modal-backdrop').not(':first').addClass('hidden');
that.adjustBackdrop();
});
};
MultiModal.prototype.hidden = function (target) {
this.modalIndex--;
this.adjustBackdrop();
if ($('.modal.in').length === 1) {
/* Reset the index to 1 when only one modal dialog is open */
this.modalIndex = 1;
$('.modal.in').css('z-index', MultiModal.BASE_ZINDEX + 10);
var $modalBackdrop = $('.modal-backdrop:first');
$modalBackdrop.removeClass('hidden');
$modalBackdrop.css('z-index', MultiModal.BASE_ZINDEX);
}
};
MultiModal.prototype.adjustBackdrop = function () {
$('.modal-backdrop:first').css('z-index', MultiModal.BASE_ZINDEX + (this.modalIndex * 20));
};
MultiModal.prototype.collateZIndex = function () {
var index = 1;
var $modals = $('.modal.in').toArray();
$modals.sort(function(x, y)
{
return (Number(x.style.zIndex) - Number(y.style.zIndex));
});
for (i = 0; i < $modals.length; i++)
{
$($modals[i]).css('z-index', MultiModal.BASE_ZINDEX + (index * 20) + 10);
index++;
};
this.modalIndex = index;
this.adjustBackdrop();
};
function Plugin(method, target) {
return this.each(function () {
var $this = $(this);
var data = $this.data('multi-modal-plugin');
if (!data)
$this.data('multi-modal-plugin', (data = new MultiModal(this)));
if (method)
data[method](target);
});
}
$.fn.multiModal = Plugin;
$.fn.multiModal.Constructor = MultiModal;
$(document).on('show.bs.modal', function (e) {
$(document).multiModal('show', e.target);
});
$(document).on('hidden.bs.modal', function (e) {
$(document).multiModal('hidden', e.target);
});}(jQuery, window));

Categories

Resources