0

I have 2 ajax request on my function. The second ajax is working properly but the result is not appending to my div. This is my code. Any help would be appreciated.

function load_candidates() {
  $.ajax({
    url: 'admin/requests/Get-Positions.php',
    method: 'POST',
    data: {
      id: id
    },
    dataType: 'json',
    success: function(result) {
      var textToInsert = '';

      $.each(result, function(key, value) {
        var position_id = value['id'];
        textToInsert += '<div class="card bg-primary text-center"><div class="card-body"><h4 class="text-white m-0" id="position">' + value['position'] + '</h4></div></div><br><div class="row">';
        $.ajax({
          url: 'admin/requests/Get-Candidate_Per_Position.php',
          method: 'POST',
          data: {
            position_id: position_id
          },
          dataType: 'json',
          success: function(data) {
            $.each(data, function(key, value) {
              textToInsert += '<div class="col-lg-4 col-sm-6 text-center mb-4"><h3>' + value['name'] + '</h3><p>' + value['candidate_number'] + '</p></div>';
            });
          }
        });
        textToInsert += '</div>';
      });
      $('#candidate_list').append(textToInsert);
    },
    error: function(xhr, status, error) {
      console.log(xhr.responseWithJSON)
    }
  });
}
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
Sonson Ixon
  • 385
  • 1
  • 5
  • 17
  • Your appending before getting result from second ajax request. Move your $('#candidate_list').append(textToInsert); to the second ajax success call – Sagar Dec 18 '17 at 11:39
  • That'll help, but also you're closing your divs in a loop straight after each AJAX call (not completion), so you'll get the opening and closing Divs for each loop in textToInsert and then ASYNCHRONOUSLY the iterative responses will be appended afterwards. – Matt_S Dec 18 '17 at 11:42
  • @Sagar That was what I was going to answer (and also move `textToInsert += '';` to that same callback). But not sufficient. From the $.each one can tell that he's firing several AJAX requests to get each position's candidates. Using async: false might help but you'll have performance issues since you'll fire several requests in a row and wait for each of them to return. I'd suggest using a flow control library such as [async](http://caolan.github.io/async/docs.html#map) (especially look at async.map), or better yet, promises (I can provide code example if needed). – Benito Dec 18 '17 at 11:44
  • Thank you I think im getting closer. I get what I want but the result is doubled. Where do you think i go wrong? Thanks btw sagar. – Sonson Ixon Dec 18 '17 at 11:45
  • I think you have double results because you're appending `textToInsert` to the div as many times as you have positions. – Benito Dec 18 '17 at 11:46
  • @benito please do so. That would be very much appreciated. After following sagar suggestion, I get; Position 1 Candidate 1 , Candidate 2 etc... Position 1 Candidate 1 , Candidate 2 etc... I dont quite get where my loop is wrong. – Sonson Ixon Dec 18 '17 at 11:48

5 Answers5

1

Here's the output from the each() over the first response being written in order correctly:

  var textToInsert = '';

  $.each(result, function(key, value) {
    var position_id = value['id'];

    $.ajax({
      url: 'admin/requests/Get-Candidate_Per_Position.php',
      method: 'POST',
      data: {
        position_id: position_id
      },
      dataType: 'json',
      success: function(data) {
        textToInsert += '<div class="card bg-primary text-center"><div class="card-body"><h4 class="text-white m-0" id="position">' + value['position'] + '</h4></div></div><br><div class="row">';
        $.each(data, function(key, value) {
          textToInsert += '<div class="col-lg-4 col-sm-6 text-center mb-4"><h3>' + value['name'] + '</h3><p>' + value['candidate_number'] + '</p></div>';
        });
        textToInsert += '</div>';
        $('#candidate_list').html(textToInsert);
      }
    });
  });
Matt_S
  • 315
  • 1
  • 7
  • After trying this as @sagar suggestion, I get double result. I dont quit get where I go wrong. – Sonson Ixon Dec 18 '17 at 11:53
  • Try printing some debug to the console inside your loop to see if there is any repetition in the calls. Something simple like console.log("Requested "+position_id); – Matt_S Dec 18 '17 at 11:57
  • Actually, @Benito has it - you are appending to the textToInsert string, and then you are appending that complete string to the #condidate_list each time. You want to replace it in the #candidate_list update using $('#candidate_list').html(textToInsert); – Matt_S Dec 18 '17 at 11:59
  • Thank you for answering. I try putting some debug log and it seem like its doing ok. I get positions 3, 4 and 5. Results I want. No repetition or something alike. But still getting double result. – Sonson Ixon Dec 18 '17 at 12:01
  • I updated the code in my answer to show the update rather than append – Matt_S Dec 18 '17 at 12:02
  • THAT DO THE TRICK. Can you please bother explaining to me why html $('#candidate_list').html(textToInsert); fix my code? Whats wrong with append and why is the double result happening. Thank you for your time. – Sonson Ixon Dec 18 '17 at 12:03
  • The candidate_list contains your desired output at the end of each iteration. If you *append* the texttoinsert again, you'll add all that as well as the next iteration content, replicating all that went before on every iteration. Thus, all you need do is replace the candidate_list in totality with texttoinsert (which is what html() does rather than append().) Perhaps you are thinking the textToInsert only has the latest result in it, which is not the case the way this is written at present. – Matt_S Dec 20 '17 at 10:51
0

you append the result before the ajax request is finished. which means TextToInsert is still empty at that moment. it's either put async:false or append the result inside the ajax request

Driss BIYA
  • 31
  • 3
  • Thank you for answering but after trying both options i get double result. I get what i want though. Only problem is its doubled. – Sonson Ixon Dec 18 '17 at 11:55
0

Thank you for answering and giving me a bit of your time. This helped me alot. Thank you guys. The .html(textToInsert) to the trick. I dont know why though. Im a bit new to jquery. Anyways. Thank you guys. I really appreciate this. More powers

Sonson Ixon
  • 385
  • 1
  • 5
  • 17
0

Here is an answer that uses the async library. It's very useful when you have to perform a chain of asynchronous operations.

In order to use it, you have to include async.js or async.min.js in yout HTML code. You may find script links on CDNJS.

Here I only use the async.map() function. The idea is that it executes the load_candidate function (2nd argument) for each item in the position_ids array. So all AJAX requests are fired at the same time. But it waits for all of them to complete, and gets all requests results in an array.

I'm aware using this kind of library might look a bit scary, but honestly, if you ever have to do some kind of complex code, with many asynchronous calls, some depending on the results of previous ones, this is worth looking into.

I took the liberty to refactor your code into smaller, more specific functions. I tested it in my browser and it works, just remember that your id variable must be defined somewhere before you call load_candidates().

function load_position(id, cbSuccess, cbError) {
  $.ajax({
    url: 'admin/requests/Get-Positions.php',
    method: 'POST',
    data: {
      id: id
    },
    dataType: 'json',
    success: cbSuccess,
    error: cbError
  });  
}

function load_candidate(position_id, callback) {
  $.ajax({
    url: 'admin/requests/Get-Candidate_Per_Position.php',
    method: 'POST',
    data: {
      position_id: position_id
    },
    dataType: 'json',
    success: function(result) {
      callback(null, result);
    },
    error: function(xhr, status, error) {
      callback(new Error('Error in 2nd request: ' + xhr.responseText));
    }
  });
}

function ajax_error_handler(xhr, status, error) {
  console.log(xhr.responseText);
}

function load_candidates(id) {

  // Fires the 1st request
  load_position(id, function(result1) {

    // This extracts all position ids from the result of 1st request
    var position_ids = result1.map(function(value) {
      return value.id;
    });

    async.map(position_ids, load_candidate, function(err, result2) {
      // Abort on error
      // This will be called if ANY of the individual load_candidate() request fails
      if(err) {
        console.log(err);
        return;
      }
      // result2 is now an array of results of each AJAX request

      result1.forEach(function(value1, index1) {

        // Create your outer div
        var textToInsert = '';
        textToInsert += '<div class="card bg-primary text-center"><div class="card-body"><h4 class="text-white m-0" id="position">' + value1['position'] + '</h4></div></div><br><div class="row">';
        // append each result of 2nd request to that div 
        result2[index1].forEach(function(value2, key) {
          textToInsert += '<div class="col-lg-4 col-sm-6 text-center mb-4"><h3>' + value2['name'] + '</h3><p>' + value2['candidate_number'] + '</p></div>';
        });

        // then close it and append it to your list
        textToInsert += '</div>';
        $('#candidate_list').append(textToInsert);

      });

    });
  },
  ajax_error_handler);
}

// Your id variable has to be defined somewhere
load_candidates(id);
Benito
  • 710
  • 5
  • 10
-1

Use async property in your second ajax request and set it to false. AJAX requests are asynchronous by default. They won't wait until the response comes from the server.

Replace your second ajax with the following:

$.ajax({
url: 'admin/requests/Get-Candidate_Per_Position.php',
method: 'POST',
data: {
    position_id: position_id
},
dataType: 'json',
async: false,
success: function(data) {
    $.each(data, function(key, value) {
        textToInsert += '<div class="col-lg-4 col-sm-6 text-center mb-4"><h3>' + value['name'] + '</h3><p>' + value['candidate_number'] + '</p></div>';
    });
}});

For your reference:

  1. http://api.jquery.com/jQuery.ajax/
  2. https://stackoverflow.com/a/1478322/3910232
Sam G
  • 1,242
  • 15
  • 12
  • Forcing synchronous loading is a bit of an over-the-top approach and could result in very clunky loading if the list is long... – Matt_S Dec 18 '17 at 12:01