Bootstrap modal on form submit not displaying at correct point

Tags: , , ,



Requirement

I want to display a fixed message to the user whilst a file is being uploaded and attached to an email to discourage clicking back or refreshing the page or repeatedly clicking the submit button.

Background

I’m using bootstrap v3.3.7 and JQuery v3.3.1.

I thought a good way to tackle this requirement was to make use of the Bootstrap Modal plugin, especially when I realised you could fix the modal on screen using:

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

I have the following modal:

@model Web.ViewModels.Site.Foo.FooViewModel
<div class="modal fade" id="modal-foo" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true" style="display: none;">
    <div class="modal-dialog">
        <div class="modal-content">
            <!-- Modal Header -->
            <div class="modal-header">
                <h4 class="modal-title" id="modal-label">
                    <i class="fa fa-spin fa-spinner"></i> Uploading your file and submitting it for review
                </h4>
            </div>

            <!-- Modal Body -->
            <div class="modal-body">
                <p>We're currently uploading and submitting your file for review.</p>
                <p>This may take a few moments. Please do not hit the back button or try to refresh this page whilst this is happening.</p>
            </div>
        </div>
    </div>
</div>

I have the following form:

<form id="fooform" asp-action="fooaction" asp-controller="foocontroller" asp-route-fooid="@Model.FooId" method="post" enctype="multipart/form-data" class="form-horizontal">

I have the following button:

<input type="submit" value="Submit" class="btn btn-primary" />

And the following jquery:

//when dom loaded hooks
$.when($.ready).then(function () {
  $('#fooform').on('submit', function () {
     if ($(this).valid()) {
        //we've passed the unobtrusive validation so now present the message to the user
        $("#modal-foo").modal({
          backdrop: 'static',
          keyboard: false
        });
     }
   });
})

Issue

What I was hoping would happen is that the modal would appear once the unobtrusive validation has passed, and is displayed until the user is redirected to a thank you page.

What I’m finding happen is that the modal isn’t appearing until later in the process.

For example, if I put some alerts in to see what’s happening, using the code below, the modal doesn’t appear until after ‘here3’. It’s as though the .modal is firing an instruction to browser to display the modal but it doesn’t action it immediately.

//when dom loaded hooks
$.when($.ready).then(function () {
  $('#fooform').on('submit', function () {
     alert('here1');
     if ($(this).valid()) {
        //we've passed the unobtrusive validation so now present the message to the user
        alert('here2');
        $("#modal-foo").modal({
          backdrop: 'static',
          keyboard: false
        });
        alert('here3');
     }
   });
})

Alternative attempt to achieve requirement

I’ve tried using an anchor instead of a submit button but again, the modal doesn’t appear until after ‘here3’:

<a class="btn btn-primary" onclick="showModal();">Submit</a>

Javascript function:

function showModal() {
  if ($('#fooform').valid()) {
    //we've passed the unobtrusive validation so now present the message to the user
    alert('here1');
    $("#modal-foo").modal({
      backdrop: 'static',
      keyboard: false
    });
    alert('here2');
    //can I somehow wrap the submit in a promise or delegate so that after the modal appears it does the submit?
    $('#fooform').submit();
    alert('here3');
  }
}

Question

How can I achieve my requirement? As per my comment in the Javascript function above, can I wrap the form submit in a promise or delegate or can I set something on the DOM to fire after the modal has displayed or is there an alternative to the Modal that I should look at?

Answer

In the end I got this working by using the following. Hopefully, someone else may find this useful:

Same button and form

<input type="submit" value="Submit" class="btn btn-primary" />

<form id="fooform" asp-action="fooaction" asp-controller="foocontroller" asp-route-fooid="@Model.FooId" method="post" enctype="multipart/form-data" class="form-horizontal">

Modal

Note the additional data-backdrop and data-keyboard attributes on the 1st div

@model Web.ViewModels.Site.Foo.FooViewModel
<div data-backdrop="static" data-keyboard="false" class="modal fade" id="modal-foo" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true" style="display: none;">
    <div class="modal-dialog">
        <div class="modal-content">
            <!-- Modal Header -->
            <div class="modal-header">
                <h4 class="modal-title" id="modal-label">
                    <i class="fa fa-spin fa-spinner"></i> Uploading your file and submitting it for review
                </h4>
            </div>

            <!-- Modal Body -->
            <div class="modal-body">
                <p>We're currently uploading and submitting your file for review.</p>
                <p>This may take a few moments. Please do not hit the back button or try to refresh this page whilst this is happening.</p>
            </div>
        </div>
    </div>
</div>

jQuery

I ended up taking the key elements from the modal plugin in the Bootstrap js file and the modal appeared at the point I expected it to whilst still giving me the modal display effects that I was looking for.

function showModal() {
    var $body = $("body");
    $body.addClass("modal-open");
    $(document.createElement('div'))
        .addClass('modal-backdrop fade in')
        .appendTo($body)
    var $modal = $("#modal-foo");
    $modal.show();
    $modal.scrollTop(0);
    $modal[0].offsetWidth;
    $modal.addClass('in');
}

//when dom loaded hooks
$.when($.ready).then(function () {
    $('#fooform').on('submit', function () {
        if ($(this).valid()) {
            showModal();
        }
    });
})



Source: stackoverflow