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);