skip to Main Content

I have page in my application that displays status. The status is displayed in drop down menu with two options Active/Inactive. The user can change the status by simply clicking on the menu and choosing the option. For that process I use JQuery/Ajax onchange trigger to track status change. The code is working fine and saves the value in datatbase. The issue I’m experiencing is related to bootbox and displaying loading message. When user clicks on the menu and changes the status ajax will send the request. At that point dialog window will show on the user screen with the loading message. Once ajax request is complete loading dialog should hide and display message tot he user that status successfully saved. Here is the code example:

function alertBox(title, message, size) {
  title = title || "Alert";
  message = message || "Alert Box";
  size = size || "lg";

  bootbox.alert({
    size: size,
    title: title,
    message: message
  });
};

$('.status').on('change', function() {
  let $curr_fld = $(this),
    status_id = $curr_fld.attr('data-id'),
    dialog = bootbox.dialog({
      message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Loading...</p>',
      closeButton: false
    });

  $curr_fld.prop("disabled", true);
  /*** Start: This is a code for testing. ***/
  /*
  setTimeout(function() {
    dialog.modal('hide');
    $curr_fld.prop("disabled", false);
    alertBox('Alert Message', status_id);
  }, 3000);
  */
  /*** End: This is a code for testing. ***/
  
  $.ajax({
    type: 'POST',
    url: 'test.php?id=1',
    data: {
      'status_id': status_id
    },
    dataType: 'json'
  }).done(function(obj) {
    dialog.modal('hide');
    $curr_fld.prop("disabled", false);
    if (obj.status === 200) {
      alertBox('Alert Message', obj);
    } else {
      alertBox('Alert Message', obj);
    }
  }).fail(function(jqXHR, textStatus, errorThrown) {
    $curr_fld.prop("disabled", false);
    alertBox('Error', textStatus);
  });

});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js"></script>

<table class="table table-striped table-bordered" id="tbl_nofa">
  <thead>
    <tr class="bg-dark">
      <th class="text-center text-white">Section</th>
      <th class="text-center text-white">Status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="text-center"> South</td>
      <td class="text-center">
        <select class="custom-select status" name="status_1" id="status_1" data-id="1">
          <option value="A" selected>Active</option>
          <option value="I">Inactive</option>
        </select>
      </td>
    </tr>
    <tr>
      <td class="text-center"> North</td>
      <td class="text-center">
        <select class="custom-select status" name="status_2" id="status_2" data-id="2">
          <option value="A">Active</option>
          <option value="I" selected>Inactive</option>
        </select>
      </td>
    </tr>
    <tr>
      <td class="text-center"> East</td>
      <td class="text-center">
        <select class="custom-select status" name="status_3" id="status_3" data-id="3">
          <option value="A" selected>Active</option>
          <option value="I">Inactive</option>
        </select>
      </td>
    </tr>
    <tr>
      <td class="text-center"> West</td>
      <td class="text-center">
        <select class="custom-select status" name="status_4" id="status_4" data-id="4">
          <option value="A">Active</option>
          <option value="I" selected>Inactive</option>
        </select>
      </td>
    </tr>
  </tbody>
  <tfoot>
    <tr class="bg-dark">
      <th class="text-center text-white">Section</th>
      <th class="text-center text-white">Status</th>
    </tr>
  </tfoot>
</table>

If you run code example above, you will see once the ajax request is complete loading dialog is still on the screen. I’m not sure why since I have .modal('hide') in place. If you comment out the block of code with setTimeout and comment out the ajax code you will see that loading dialog works just fine. If anyone knows how to solve this issue please let me know.

2

Answers


  1. I noticed a couple of issues:

    1. You’ll want to close the dialog from the always function of your ajax call. When testing the fail would occur, but you had no code to close the dialog. However this still didn’t fix the problem.
    2. This appears to be an issue with the boostrap modal. What’s happening is that the hide function is being called too soon before the animation completes. There are two solutions to work around this issue:

      1. Disable the animation by using animate: false.
      2. Add code that detects if the animation is complete, and if it isn’t, act appropriately in the always function.
    $('.status').on('change', function() {
      let $curr_fld = $(this),
        loading_shown = false,
        status_id = $curr_fld.attr('data-id'),
        dialog = bootbox.dialog({
          // animate: false, // <-- simple way that makes the issue go away.
          message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Loading...</p>',
          closeButton: false,
        }).on('shown.bs.modal', () => loading_shown = true);
    
      $curr_fld.prop("disabled", true);
    
      $.ajax({
        type: 'POST',
        url: 'test.php?id=1',
        data: {
          'status_id': status_id
        },
        dataType: 'json'
      }).done(function(obj) {
        $curr_fld.prop("disabled", false);
        if (obj.status === 200) {
          alertBox('Alert Message', obj);
        } else {
          alertBox('Alert Message', obj);
        }
      }).fail(function(jqXHR, textStatus, errorThrown) {
        $curr_fld.prop("disabled", false);
        alertBox('Error', textStatus);
      }).always(() => {
        // hide immediately, or wait until the animation is complete by listening
        // to shown.bs.modal.
        loading_shown 
          ? dialog.modal('hide')
          : dialog.on('shown.bs.modal', () => dialog.modal('hide'));
      }); 
    });
    
    

    There might be more succinct ways to handle the animation issue without disabling the animation itself. This was just one method.

    Login or Signup to reply.
  2. As per Daniel Gimenez, the issue is that dialog.modal('close') get’s called very soon a easy fix to this will be to use setTimeout() , this will allow you to keep those fancy animations also:

    Replace all dialog.modal('hide') with

    setTimeout(function(){ 
       dialog.modal('hide')
    },200);
    

    Hence your complete code will be:

    function alertBox(title, message, size) {
      title = title || "Alert";
      message = message || "Alert Box";
      size = size || "lg";
    
      bootbox.alert({
        size: size,
        title: title,
        message: message
      });
    };
    
    $('.status').on('change', function() {
      let $curr_fld = $(this),
        status_id = $curr_fld.attr('data-id'),
        dialog = bootbox.dialog({
          message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Loading...</p>',
          closeButton: false
        });
    
      $curr_fld.prop("disabled", true);
      /*** Start: This is a code for testing. ***/
      /*
      setTimeout(function() {
        dialog.modal('hide');
        $curr_fld.prop("disabled", false);
        alertBox('Alert Message', status_id);
      }, 3000);
      */
      /*** End: This is a code for testing. ***/
      
      $.ajax({
        type: 'POST',
        url: 'test.php?id=1',
        data: {
          'status_id': status_id
        },
        dataType: 'json'
      }).done(function(obj) {
        setTimeout(function(){ 
            dialog.modal('hide')
            $curr_fld.prop("disabled", false);
            if (obj.status === 200) {
              alertBox('Alert Message', obj);
            } else {
              alertBox('Alert Message', obj);
            }
        },200);
        
      }).fail(function(jqXHR, textStatus, errorThrown) {
        setTimeout(function(){ 
            dialog.modal('hide')
            $curr_fld.prop("disabled", false);
            alertBox('Error', textStatus);
        },200);
       
      });
    
    });
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js"></script>
    
    <table class="table table-striped table-bordered" id="tbl_nofa">
      <thead>
        <tr class="bg-dark">
          <th class="text-center text-white">Section</th>
          <th class="text-center text-white">Status</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td class="text-center"> South</td>
          <td class="text-center">
            <select class="custom-select status" name="status_1" id="status_1" data-id="1">
              <option value="A" selected>Active</option>
              <option value="I">Inactive</option>
            </select>
          </td>
        </tr>
        <tr>
          <td class="text-center"> North</td>
          <td class="text-center">
            <select class="custom-select status" name="status_2" id="status_2" data-id="2">
              <option value="A">Active</option>
              <option value="I" selected>Inactive</option>
            </select>
          </td>
        </tr>
        <tr>
          <td class="text-center"> East</td>
          <td class="text-center">
            <select class="custom-select status" name="status_3" id="status_3" data-id="3">
              <option value="A" selected>Active</option>
              <option value="I">Inactive</option>
            </select>
          </td>
        </tr>
        <tr>
          <td class="text-center"> West</td>
          <td class="text-center">
            <select class="custom-select status" name="status_4" id="status_4" data-id="4">
              <option value="A">Active</option>
              <option value="I" selected>Inactive</option>
            </select>
          </td>
        </tr>
      </tbody>
      <tfoot>
        <tr class="bg-dark">
          <th class="text-center text-white">Section</th>
          <th class="text-center text-white">Status</th>
        </tr>
      </tfoot>
    </table>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search