1

I’m using JQuery with HTML to create a button that when clicked, loads table rows.

My HTML:


<div class="load-more-container">
<button id="btn-load-more">Load More</button>
</div>
<p id="loading" style="display:none"> Loading ... </p>

My js:


$("#btn-load-more").on("click", function (event) {
   event.preventDefault();
   $("#btn-load-more").prop("disabled", true)
   $("#loading").show();
   //loading table rows
   $("#btn-load-more").prop("disabled", false)
   $("#loading").hide();
})

I want my button to be disabled when I click on it, and a “Loading…” text will be displayed.

After loading finishes, I want to enable my button again and hide the “Loading…” text.

Currently, the “Loading…” text is only shown after the rows are loaded and not when the rows are loading(my intent).

Can anyone advice me on what’s wrong with my js? Appreciate it!

Edit: Here is a minimum reproducible example. The Loading p tag is not showing when I click on the button with the provided JS code.

$(document).ready(function (){
  $("#my-table-tbody tr").slice(2).hide()
  if ($("#my-table-tbody tr:hidden").length == 0){
    $("#btn-load-more").hide()
  }

  $("#btn-load-more").on("click", function (event) {
    event.preventDefault();
    $("#loading").show();


    $("#my-table-tbody tr:hidden").slice(0,2).slideDown("fast", function(){
      $("#loading").hide();
    })
  })
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>

<div>
<table id="my-table">

<thead>

<tr>
    <th>Company</th>
    <th>Contact</th>
    <th>Country</th>
</tr>
</thead>
<tbody>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
</tbody>
</table>

<button id="btn-load-more" style="cursor: pointer">Load More</button>

    
<p id="loading" style="text-align:center; display:none"> Loading ... </p>
</div>

3
  • Remember that javascript is single-threaded - this means it can only do one thing at a time and that includes updating the UI. So whenever you have code that does "disable-dosomething-enable" - the "disable" will never occur as it will be enabled before being updated. You need to show your loader, then initiate the loading (eg with a settimeout) and then hide the loader when loading has completed. Commented Dec 20, 2022 at 13:48
  • @freedomn-m Thanks, I have a question as to your implementation. How will I know how much time to set for settimeout an do I initiate the loading in the button onclick function? Commented Dec 20, 2022 at 14:11
  • I wasn't clear: showLoader(); setTimeout(loadRows, 1); function loadRows() { .... hideLoader(); } - don't close the loader on the timeout Commented Dec 20, 2022 at 14:18

1 Answer 1

1

This depends on what this "line of code" actually does:

//loading table rows

If this is a synchronous operation (such as building a bunch of HTML from data you already have) then there isn't much you can do. JavaScript is single-threaded, so this process:

  1. Change the UI to "loading"
  2. Perform synchronous, CPU-intensive operation
  3. Change the UI to "not loading"

This will result in no visual appearance of the first UI update, because the thread is busy performing all of the other operations and then processing the second UI update. So by the time the screen re-draws, only the latest UI is seen.

However, if "loading table rows" is an asynchronous process (such as fetching data via AJAX), then you certainly can temporarily show something in the UI. In this case it depends on how you structure that asynchronous operation.

Since nothing here is async then I assume we're not using async and await. The use of jQuery here suggests a callback-based structure. In that case the second UI update would just need to go in that callback.

For example, if we substitute your asynchronous operation with something simple like setTimeout just to demonstrate, we see how we can put that code in the callback:

$("#btn-load-more").on("click", function (event) {
   event.preventDefault();

   // 1: Show the loader
   $("#btn-load-more").prop("disabled", true)
   $("#loading").show();

   // 2: Invoke the asynchronous operation, whatever it may be
   setTimeout(function () {

       // 3: Hide the loader
       $("#btn-load-more").prop("disabled", false)
       $("#loading").hide();

   }, 3000);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="load-more-container">
  <button id="btn-load-more">Load More</button>
</div>
<p id="loading" style="display:none"> Loading ... </p>

Here we see that the "Loading" state is displayed for 3 seconds and then removed. Whatever your asynchronous operation is, you'd essentially structure the code as:

  1. Change the UI to "loading"
  2. Invoke the asynchronous operation
  3. In the calllback, change the UI to "not loading"
Sign up to request clarification or add additional context in comments.

10 Comments

thanks for the detailed answer! If my loading of table rows is simply just $("#table-tbody tr:hidden").slice(0,50).slideDown() to reveal previous table rows that were hidden, is it a synchronous operation since the elements are already present in the HTML in the first place?
@codingismypassion: Take a look at the documentation for slideDown in that case, particularly the part about the callback function to be invoked when the animation completes. Structurally that's no different from the example above.
I have actually givenslidedown a try. However, if i include the showing of the loader in the callback function, the loader is only shown after the slidedown event is completed and not during the sliding down action.
@codingismypassion: The idea is to show the loader before the operation, and then hide the loader in the callback (which happens after the operation). Showing the loader after the operation wouldn't make much sense.
I got the rough idea, basically once a selector is being executed, the other selector must wait for the first to complete? (correct me if I'm wrong, so in this case the button's operation has to complete before my loader even shows, so I have to show the loader before the operation?) However, it makes no sense for a loader to be shown before I click the button?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.