Reputation: 746
I currently have setup a AJAX to PHP set of functions that processes a number of items on a page. Basically the code inserts a series of tasks into the database, then inserts supplies into the database based on those newly created task ID's. However it works 90% of the time. Sometimes it seems as though the Task ID's are not created first which doesn't allow the supplies to use those ID's for inserting into the database. Is there a way to make sure that the task is inserted, then all supplies are inserted for that ID, then move onto the next one. At the end when all is complete I would like to redirect to a new page, again I put this in the last success call on the supplies portion, but it would redirect on the first loop. This process usually generates around 5 tasks, with 12 supplies per each task. I was reading about a $.when
loop but could not get it to work. NOTE: after testing the ajax calls are submitting correctly, it was that one field on some of them was null, and the DB was having an issue. So the counter method below works.
$(document).on("click", "#submitTasks", function(e) {
e.preventDefault();
var tasks = $('#tasks').find('.box');
var project_id = $('#project_id').val();
tasks.each(function() {
var trs = $(this).find('.reqTables').find('.table').find('tbody').find('tr');
var task_definition_id = $(this).find('.task_definition_id').val();
var labor_type_id = $(this).find('.laborAmount').children('option:selected').val();
var task_status_id = 1;
var qty_labor = $(this).find('.laborQty').val();
var amount_labor = $(this).find('.laborTotal').val();
var amount_materials = $(this).find('.matTotal').val();
var amount_gst = $(this).find('.gstTotal').val();
amount_materials = +amount_materials + +amount_gst;
amount_materials = amount_materials.toFixed(2);
var active = 1;
//console.log(div)
var task = {
project_id : project_id,
task_definition_id : task_definition_id,
labor_type_id : labor_type_id,
task_status_id : task_status_id,
qty_labor : qty_labor,
amount_labor : amount_labor,
amount_materials : amount_materials,
active : active
};
saveTasks(task, trs, project_id);
});
});
function saveTasks(task, trs, project_id) {
$.ajax({
type : "POST",
url : "<?php echo base_url(); ?>" + "mgmt/project/saveTasks",
data : task,
dataType : "json",
cache : "false",
success : function(data) {
trs.each(function() {
var total = $(this).find('input[name="calculatedCost"]').val();
if (total != 'n/a') {
var task_id = data;
var supply_id = $(this).find('.suppliesPicker').children('option:selected').val();
var task_requirement_id = $(this).find('td:first-child').data('id');
var qty = $(this).find('input[name="calculatedQty"]').val();
var cost_per = $(this).find('.costPicker').val();
var delivery_cost = $(this).find('input[name="transport"]').val();
var notes = '';
var qty_actual = '';
var active = 1;
var taskSupply = {
task_id : task_id,
supply_id : supply_id,
task_requirement_id : task_requirement_id,
qty : qty,
cost_per : cost_per,
delivery_cost : delivery_cost,
total : total,
notes : notes,
qty_actual : qty_actual,
active : active
};
saveTaskSupplies(taskSupply);
console.log(taskSupply);
}
});
}
});
}
function saveTaskSupplies(taskSupply) {
$.ajax({
type : "POST",
url : "<?php echo base_url(); ?>" + "mgmt/project/saveTaskSupplies",
data : taskSupply,
dataType : "json",
cache : "false",
success : function(data) {
***** I WANT TO REDIRECT TO A NEW PAGE WHEN THE LAST ONE OF THESE COMPLETES ******
}
});
}
Upvotes: 3
Views: 4612
Reputation: 547
Regarding the first question, by studying your code I couldn't see the reason of it. You only execute the saveTaskSupplies()
when saveTasks()
has executed successfully, so the task_id
should already be created.
However, I would think of another possible problem from your backend, in your Ajax success
function in saveTasks()
, You assume the PHP script always execute successfully and return the task_id
. Would it be possible that your PHP script has some problem and the task_id
is not created in some instance?
For the second question, there are a few approaches, as @Seth suggest you can use jQuery.when, or you can create a global counter to keep track of whether the saveTaskSupplies()
is the last one. Note that you should calculate the total length of trs before firing the Ajax request, otherwise, you may have a chance of having a not well-calculated total and redirecting before all tasks are done. If it is the last one it will redirect after successful Ajax call.
// create a global counter
var counter = 0,
trl = 0;
$(document).on("click", "#submitTasks", function(e) {
...
var trList = [];
tasks.each(function() {
// calculate the length of total task before actually firing the Ajax Request
var trs = $(this).find('.reqTables').find('.table').find('tbody').find('tr');
// keep a copy of the trs so the next each loop does not have to find it again
trList.push(trs);
trl += trs.length;
});
tasks.each(function() {
// get the trs of current iteration we have found in last loop
var trs = trList.shift();
...
saveTasks(task, trs, project_id);
});
});
function saveTasks(task, trs, project_id) {
$.ajax({
...
success : function(data) {
trs.each(function() {
...
saveTaskSupplies(taskSupply);
}
}
});
}
function saveTaskSupplies(taskSupply) {
$.ajax({
...
success : function(data) {
// check if the counter exceed the length of trs
if (++counter == trl) {
location.href = 'place you want to go';
}
}
});
}
On the other hand, for your task I would also suggest shifting the responsibility of data insertion to PHP backend, so all you need to do is to pass the task information and the task supplies at once to a single PHP script. This approach allows the use of Transaction to make sure all data insertion is success or otherwise all should fail.
Upvotes: 0
Reputation: 17898
This code will wait for nested loop ajax function calls to finish their promises, then proceed..
var allPromises;
$(document).on("click", "#submitTasks", function(e) {
//...
var tasks = $('#tasks').find('.box');
allPromises = [];
tasks.each(function() {
//.. somehow getTask
var req = saveTasks(task, trs, project_id);
allPromises.push(req);
});
$.when.apply(null, allPromises).done(function(){
// Do your things here,
// All save functions have done.
});
});
function saveTasks(task, trs, project_id) {
return $.ajax({
// ,,, your codes
success : function(data) {
// ...
trs.each(function() {
// ... Somehow get taskSupply
var req = saveTaskSupplies(taskSupply);
allPromises.push(req);
}
}
});
}
function saveTaskSupplies(taskSupply) {
return $.ajax({
// ... bla bla bla
success : function(data) {
// Whatever..
}
});
}
Upvotes: 3
Reputation: 1365
Here is a direct solution using the code you provided. The basic concept is to increment a counter as supplies are processed. Once the counter reaches the total number of supplies, a procedure is run. See comments throughout.
var totalTaskSupplies = 0;
var processedTaskSupplies = 0;
$(document).on("click", "#submitTasks", function(e) {
e.preventDefault();
var tasks = $('#tasks').find('.box');
var project_id = $('#project_id').val();
tasks.each(function() {
var trs = $(this).find('.reqTables').find('.table').find('tbody').find('tr');
var task_definition_id = $(this).find('.task_definition_id').val();
var labor_type_id = $(this).find('.laborAmount').children('option:selected').val();
var task_status_id = 1;
var qty_labor = $(this).find('.laborQty').val();
var amount_labor = $(this).find('.laborTotal').val();
var amount_materials = $(this).find('.matTotal').val();
var amount_gst = $(this).find('.gstTotal').val();
// Add number of supplies for current task to total task supplies
totalTaskSupplies += trs.length;
amount_materials = +amount_materials + +amount_gst;
amount_materials = amount_materials.toFixed(2);
var active = 1;
//console.log(div)
var task = {
project_id : project_id,
task_definition_id : task_definition_id,
labor_type_id : labor_type_id,
task_status_id : task_status_id,
qty_labor : qty_labor,
amount_labor : amount_labor,
amount_materials : amount_materials,
active : active
};
saveTasks(task, trs, project_id);
});
});
function saveTasks(task, trs, project_id) {
$.ajax({
type : "POST",
url : "<?php echo base_url(); ?>" + "mgmt/project/saveTasks",
data : task,
dataType : "json",
cache : "false",
success : function(data) {
trs.each(function() {
var total = $(this).find('input[name="calculatedCost"]').val();
if (total != 'n/a') {
var task_id = data;
var supply_id = $(this).find('.suppliesPicker').children('option:selected').val();
var task_requirement_id = $(this).find('td:first-child').data('id');
var qty = $(this).find('input[name="calculatedQty"]').val();
var cost_per = $(this).find('.costPicker').val();
var delivery_cost = $(this).find('input[name="transport"]').val();
var notes = '';
var qty_actual = '';
var active = 1;
var taskSupply = {
task_id : task_id,
supply_id : supply_id,
task_requirement_id : task_requirement_id,
qty : qty,
cost_per : cost_per,
delivery_cost : delivery_cost,
total : total,
notes : notes,
qty_actual : qty_actual,
active : active
};
saveTaskSupplies(taskSupply);
console.log(taskSupply);
}
});
}
});
}
function saveTaskSupplies(taskSupply) {
$.ajax({
type : "POST",
url : "<?php echo base_url(); ?>" + "mgmt/project/saveTaskSupplies",
data : taskSupply,
dataType : "json",
cache : "false",
success : function(data) {
++processedTaskSupplies;
// All supplies have been processed
if (processedTaskSupplies == totalTaskSupplies) {
// Do something
}
}
});
}
Upvotes: 2