I have jobs site. User fills out a form and selects CV (resume) file from PC, hits the Send button. This calls a ajaxSubmit() function which does local validation (removed from the code below) and if OK, does an AJAX file upload. The server side does further validation and returns SUCCESS or ERROR (plus error text) in JSON.
When the user hits the Send button I open a modal #apply_working_modal, which just shows a spinner icon. On ajax.done, I close #apply_working_modal, and if there were errors, put them on the body of modal #apply_errors_modal and open it.
The first time I try it, with an error on purpose, it works as described. If I try it again, with the error still in place, #apply_working_modal shows and will not close until I manually click the X or away from it.
It seems to be some timing issue because when you re-submit after an error, the CV file is already on the server so the JSON comes back very fast. In fact, If I throttle the network just a bit I can make it work.
I have tried variations of waiting on modal events, and also setTimeout() to delay opening of #apply_errors_modal
function ajaxSubmit(whichForm){
$("#apply_working_modal").modal("show");
console.log('showing apply_working_modal');
var applyRequest =$.ajax({
url: postUrl,
etc: etc
});
applyRequest.done(function( data, textStatus, jqXHR ) {
console.log(data);
$("#apply_working_modal").modal("hide");
console.log("hiding #apply_working_modal ");
if (data.STATUS =='SUCCESS') {
// validation OK at server
}
else {// validation error at server
$('#apply_working_modal').on('hidden.bs.modal', function () {
$("#apply_errors_modal_body").html(data.ErrorText);
$("#apply_errors_modal").modal("show");
console.log("on hidden of #apply_working_modal");
})
}
});
}
This is the output of the console for good/bad tests:
//Expected behaviour
15:58:45.981 myscript.js:179 showing apply_working_modal
// 10 seconds pass while server uploads file and returns errors in JSON
15:58:56.696 myscript.js:206 {STATUS: "ERROR", ErrorText: "* The Comments are too short."}
15:58:56.700 myscript.js:217 hiding #apply_working_modal
15:58:56.998 myscript.js:236 on hidden of #apply_working_modal
// Problem behaviour
15:59:26.704 myscript.js:179 showing apply_working_modal
15:59:26.723 myscript.js:206 {STATUS: "ERROR", ErrorText: "* The Comments are too short."}
15:59:26.724 myscript.js:217 hiding #apply_working_modal
// #apply_working_modal never gets hidden, have to manually close it
// manual dismiss of modal after waitinf 13 secs ....
15:59:38.525 myscript.js:236 on hidden of #apply_working_modal
15:59:38.526 myscript.js:236 on hidden of #apply_working_modal
// error modal shown but logged many times?
The HTML:
<!-- apply working (spinner while sending cv) -->
<div id="apply_working_modal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"><i class="fa fa-hourglass-end"></i><span class="sr-only">Loading...</span> Sending your CV</h4>
<button type="button" class="close" data-dismiss="modal"><i class="fa fa-times-circle-o" aria-hidden="true"></i></button>
</div>
<div class="modal-body text-center">
<i class="fa fa-spinner fa-spin fa-5x fa-fw"></i><span class="sr-only">Loading...</span>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
<!-- apply errors modal-->
<div id="apply_errors_modal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 style='color:#cc0000;' class="modal-title"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> There were errors!</h4>
<button type="button" class="close" data-dismiss="modal"><i class="fa fa-times-circle-o" aria-hidden="true"></i></button>
</div>
<div id="apply_errors_modal_body" class="modal-body">
</div>
<div class="modal-footer">
<button data-dismiss="modal" type="button" style="float:left;" class="btn btn-outline-info">Cancel</button>
</div>
</div>
</div>
</div>
Update based on answer/comments below.
For the sake of clarity while posting the question I simplified the ajax request as I did not think it was the cause - in my code I used 'etc:etc' as an ajax parameter, this was to indicate I simplified the code. I am indeed using cache:false. Full call below (postUrl is set earlier in code):
var applyRequest =$.ajax({
url: postUrl,
data: postData,
type: "POST",
xhr: function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // Check if upload property exists
myXhr.upload.addEventListener('progress',progressHandler, false); // For handling the progress of the upload
}
return myXhr;
},
enctype: 'multipart/form-data',
cache: false,
processData: false, // tell jQuery not to process the data (reqd for use with FormData)
contentType: false, // tell jQuery not to set contentType
dataType: "json"
});
If you want to prevent boostrap modal from closing by those actions, you need to change the value of backdrop and keyboard configuration. The default value of backdrop and keyboard is set to true . You can change the configuration in HTML or Javascript directly.
There are few ways to close modal in Bootstrap: click on a backdrop, close icon, or close button. You can also use JavaScript hide method. Click the button to launch the modal. Then click on the backdrop, close icon or close button to close the modal.
You can prevent closing of modal dialog by setting the beforeClose event argument cancel value to true. In the following sample, the dialog is closed when you enter the username value with minimum 4 characters.
Clicking on the modal “backdrop” will automatically close the modal. Bootstrap only supports one modal window at a time.
You're right about the timing, where the modal will not be hidden if the backdrop's animation hasn't completed yet. See https://getbootstrap.com/docs/4.1/getting-started/javascript/#asynchronous-functions-and-transitions
Asynchronous methods and transitions
All API methods are asynchronous and start a transition. They return to the caller as soon as the transition is started but before it ends. In addition, a method call on a transitioning component will be ignored.
— The above quote was taken from https://getbootstrap.com/docs/4.1/components/modal/#events
(Updated answer — I removed the cache: false
stuff.)
So try hiding the modal like this:
// Wait for the modal to be made fully visible, where CSS transitions have completed.
$('#apply_working_modal').one('shown.bs.modal', function(){
$(this).modal("hide");
});
See the description of the shown.bs.modal
for more information.
Or use setTimeout()
like this:
setTimeout(function(){
$('#apply_working_modal').modal("hide");
}, 1000);
(Updated again) The above (shown.bs.modal
) works, but in my tests, only if cache
is true
. Most likely because the shown.bs.modal
has already been triggered before the .done()
is triggered. So try doing it this way:
(Another update) Sorry, I myself forgot to use the .one()
.. and secondly, I combined this with the setTimeout()
method so that the modal hiding isn't too soon..
(Aug 15th 2018) I added the missing piece — $("#apply_working_modal").modal("show");
(just in this answer; thanks @KevinSol for pointing it out!).
function ajaxSubmit(whichForm){
var modal_shown = false;
$('#apply_working_modal').one('shown.bs.modal', function(){
modal_shown = true;
});
$("#apply_working_modal").modal("show");
...
applyRequest.done(function( data, textStatus, jqXHR ) {
...
// If the modal has been *fully* visible, simply hides it.
if (modal_shown) {
$('#apply_working_modal').modal("hide");
// Else, wait until it's fully visible, and then hides it.
} else {
$('#apply_working_modal').one('shown.bs.modal', function(){
// Wait a few ms before we hide the modal.
setTimeout(function(){
$('#apply_working_modal').modal("hide");
}, 100);
modal_shown = true;
});
}
...
});
}
And here's a the updated demo for the shown.bs.modal
event, and another demo for the setTimeout()
method.
Here you should use .one()
instead of the .on()
:
//$('#apply_working_modal').on('hidden.bs.modal' // before
$('#apply_working_modal').one('hidden.bs.modal' // correct
to prevent the event handler from being triggered multiple times:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With