Reputation: 3869
I have a $.post function inside of a loop. All it does it call a php function to validate an input. If the input validates, it returns "true" (which I tested and works). At this point I use a callback to do some processing and it is not working.
For example if i am looping over three items, the callback function processes the third item three times instead of each one.
Here is my relevant code:
for (step in steps) {
var step_name = steps[step];
// grab input value
var step_answer = escape($("#" + step_name).val());
if (step_answer != "") {
// check to see if answer validates
console.log(step_name) // THIS SHOWS CORRECT VALUES: 1, 2, and 3
$.post("utility.php", {
utility: "validateAnswer",
step: step_name,
answer: step_answer
},
function(data) {
// if validation suceeds..
if (data == "true") {
console.log(step_name); // THIS SHOWS WRONG VALUES: 3, 3, and 3
correct_steps.push(step_name);
}
});
}
}
Any ideas? Thanks.
Upvotes: 1
Views: 369
Reputation: 7960
This is a problem with the way javascript does closures. Basically, when you create a variable at the top level (like you are doing), it actually just creates window.step_name which is actually a global variable and therefore the value doesn't get encapsulated in the callback.
However, if you create a variable inside a function, this does not happen. So try wrapping your code in a function and see if it works.
Simple way:
(function() {
// code here
})();
If that works you might want to consider putting your code in a named function for easier maintenance later.
Alternatively, you could just use jquery's $.each:
$.each(steps, function() {
var step_name = this;
// code from inside loop here
}
Upvotes: 2
Reputation: 124768
That is because the step_name
is declared in the for
loop, and the for
loop gets to the end before the first POST request is completed. That is, when the function inside the $.post
is executed, the loop has looped through and step_name
equals to 3. That's the nature of asynchronous calls, you can correct that if you wish by using an $.ajax
call and setting async: false
:
for (step in steps) {
var step_name = steps[step];
// grab input value
var step_answer = escape($("#" + step_name).val());
if (step_answer != "") {
// check to see if answer validates
console.log(step_name) // THIS SHOWS CORRECT VALUES: 1, 2, and 3
$.ajax(
url: "utility.php",
data: {
utility: "validateAnswer",
step: step_name,
answer: step_answer
},
async: false,
success: function(data) {
// if validation suceeds..
if (data == "true") {
console.log(step_name); // THIS SHOWS CORRECT VALUES: 1, 2, and 3
correct_steps.push(step_name);
}
});
}
}
}
There's no need to do it like this though, "utility.php" will get the right values regardless how you do it. It would be wiser to log out the response from the PHP script to get the correct result.
Upvotes: 0
Reputation: 792
The only thing I can think of is that your ajax call isn't complete until your loop is already completed and the step variable is incremented to 3.
Upvotes: 0
Reputation: 5022
I'm guessing what you're seeing is due to using a closure within a loop. Maybe try:
$.post("utility.php", {
utility: "validateAnswer",
step: step_name,
answer: step_answer
},
function(data) {
// if validation suceeds..
if (data == "true") {
console.log(this.data.step);
correct_steps.push(this.data.answer);
}
});
In the $.post callback, this
is the AJAX request object.
Upvotes: 0
Reputation: 19358
Since step_name
is a local parameter outside the post()
call, it is being modified (to 3) before the async callback fires.
Can you try passing the step_name
back down on the response? Maybe as a part of a json object like the following.
function(data) {
// if validation suceeds..
// data example: { valid: "true", step: 1 }
if (data.valid == "true") {
console.log(data.step);
correct_steps.push(data.step);
}
});
Upvotes: 0