Home > Software engineering >  Unexpected results when using asynchronous jQuery request
Unexpected results when using asynchronous jQuery request

Time:02-19

On my website I have a table with some "add" links. By clicking on the add links, a ajax request is fired and - as soon as this request has been performed - a new table row directly below the "add" link row is created.

When clicking only one "add" link at a time, the script is working as expected.

However the script called by the get request has an execution time of approximately 2 seconds. So it might happen, that requests run parallel.

In case I am clicking on the second "add" link while the first one is still loading, the two new rows both are added below the second table row. On the other way, when clicking the first "add" link while the second one is still loading, both new rows are added below the first table row. (so in between the two add links).

This is not the behaviour I wanted to have: I am expecting, that when clicking both "add" links I am getting a new row after each of the rows.

I guess this might happen, because the variable "click" is overwritten when loading the second response while the first response is still running? How can I prevent this behaviour?

$('a.open').bind('click', function () {
      id=$(this).attr('id');
      click=$(this);
      
      $.get("#", {key:id})
      .done(function( data ) {
          text=data.html;
          click.closest('tr').after('<tr><td></td><td>' text '</td></tr>');
      })
      .fail(function (jqXHR, textStatus) {
                    click.closest('tr').after('<tr><td></td><td>error</td></tr>');
      });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<table border=1>
  <tr>
  <td><a href="#" id="12333" >add</a></td>
    <td>some text</td>
  </tr>
    <tr>
  <td><a href="#" id="23457" >add</a></td>
    <td>some other text</td>
  </tr>
</table>

CodePudding user response:

The problem is indeed that the id and click values are overwritten before the AJAX call can finish.

This happens because you don't use a variable keyword, like var, let or const to declare your variable. Therefor id and click will be assigned as properties to the window object. You can test it out by logging window.id inside the function.

$('a.open').on('click', function() {
  id = $(this).attr('id');
  console.log(window.id); 
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<table border=1>
  <tr>
    <td><a href="#" id="12333" >add</a></td>
    <td>some text</td>
  </tr>
  <tr>
    <td><a href="#" id="23457" >add</a></td>
    <td>some other text</td>
  </tr>
</table>

You can solve this by using const or let. Both are block-scoped local variables, which means that they only exist within the scope they're in. In this case they only exist within the function() { ... } that handles your click event.

var will do too, but I would recommend looking at the former two as they allow more control with scoping.

$('a.open').on('click', function() {
  const id = $(this).attr('id');
  const click = $(this);
    
  setTimeout(function() {
    click.closest('tr').after('<tr><td></td><td>Foobar</td></tr>');
  }, 3000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<table border=1>
  <tr>
    <td><a href="#" id="12333" >add</a></td>
    <td>some text</td>
  </tr>
  <tr>
    <td><a href="#" id="23457" >add</a></td>
    <td>some other text</td>
  </tr>
</table>

  • Related