This is the block that checks if returned value = 1:
} else if (validateUsername(username.val()) == 1) {
errors.html("That username already exists! Please use another.<span id='close'>X</span>");
errors.fadeIn("slow");
username.css("border", "solid 2px red");
}
If yes, username exists..
Now let's do the ajax work.
function validateUsername(username) {
$.post("js/ajax/ajax.php", { validateUsername : username }, function(data) {
return data;
});
}
This will send a request to ajax, and fill var data with the response.
if (isset($_POST['validateUsername']))
{
echo 1;
}
this is the ajax that will send a response, basically it's int 1 for now, for checking.
But, I always get undefined.
I mean, fireBug does say "request=1", but it looks like the if statement won't work.
If I just do return 1; manually without ajax, it will work.
Why is it doing that?
Ajax is asynchronous, so when you return data here :
function validateUsername(username) {
$.post("js/ajax/ajax.php", { validateUsername : username }, function(data) {
return data;
});
}
and try getting it here :
validateUsername(username.val()) == 1
it won't work, as the ajax call hasn't completed yet (and the return returns from the inner function only).
Instead you should do:
function validateUsername(username) {
return $.post("js/ajax/ajax.php", { validateUsername : username });
}
validateUsername(username.val()).done(function(data) {
if ($.trim(data) === 1) {
errors.html("That username already exists! Please use another.<span id='close'>X</span>");
errors.fadeIn("slow");
username.css("border", "solid 2px red");
}
});
Ajax functions are asynchronous. validateUsername() returns before the ajax call is complete (without a return value, which is why you see undefined).
Probably the most elegant way to handle this would be to refactor to return $.ajax... and work with the Deferred object that is returned.
AJAX stands for Asynchronous JavaScript And XML. Ignore the XML part, but the Asynchronous is what's biting you in the backside here.
Anything that depends on the result of an ajax call must be in the success handler, called by the success handler, or defined in such a way that it will only be run after the success handler.
Related
I got a question concerning asynchronous calls. What I try to do is validate if a given "code" is valid. Refreshing the page is not an option.
The case in a nutshell:
I need to set a variable to true or false based on the reply from the server.
That call is done by using ajax.
The ajax ($.post) request processes the reply from the server and thus sets the variable to true or false.
The value of the variable will then be used as the return value for that function, true or false.The problem is to only return AFTER the ajax has completed. The asynchronous behavior of ajax prevents this and hanging the browser is not done.
The validation is done by using a function (it will en up being used in an if).
The if looks the following:
if(codeGiven()) {
// Code ok. Continue to process
} else { msgCodeInvalid(); }
The function codeGiven is the following
function codeGiven(toChk) {
var codeOK = false; // default answer
if(toChk) { // only perform call if toChk is not "" of undefined
$.post(
"validate.aspx", // server script
{ code: toChk }, // value
function(data) { // function
if(data == "true") {
codeOK = true; // when true => return will be true
} else {
codeOK = false; // when false => return will be false
}
}
);
}
return codeOK; // will be false by default but true when the code is OK
}
the aspx will use the posted "code" and match it against other codes in my database. If a match is found, the reply will be "true". If not, the reply will be "false".
Because an ajax call ($.post) is asynchronous, the result will always be false.
Any suggestions on how to hack my way out of this, besides my idea with a setInterval (a dirty method I know)? A return inside the post didn't work.
Any ideas?
Thanks in advance
Final solution
I came to the realization that I could put my entire logic inside the $.post.
so basically, my logic is the following (warning, it's a deep tree structure):
if(myvar) { // if pid not empty
$.post( // start validation
"validator.aspx", // server side validation script
{ code : myvar }, // data to be passed to the server
function(data, status) { // execute when post happend
if(data == "true") { // if answer from server == "true"
/*
assign variables
apply other logic
process effects
...
*/
} else { /* if answer from server == "false" => error: invalid code given */ }
}
).error( /* error: validator did a boom boom. We're sorry :( */ );
} else { /* error: please enter a code */ }
Do your check in the callback or promise of your function, for example:
function checkCodeGiven(toChk) {
return $.post("validate.aspx", { code: toChk });
}
And then something like:
checkCodeGiven(someVar).then(function(data) {
if(data == "true") {
// do whatever you wanted to do for true
} else {
// do whatever you wanted to do for false
}
});
you can :
. call the function you want inside the success function of the ajax
OR
. the delayer way :calling the part where you need the if(codeGiven) many times with delays about 100ms so you are sure that it's false or it becomes true at one call, replace this part
if(codeGiven()) {
// Code ok. Continue to process
} else { msgCodeInvalid(); }
with codeGiven();Delayer(0); and declair this
function Delayer(counter) {
if (codeOK) {
// Code ok. Continue to process
} else if (counter <10) { //not sure if it may become true later
setTimeout(Delayer, 100, counter++);} //call after 0.1 sec
else {
msgCodeInvalid(); // no hope to be true
}
}
plus codeOK should be declaired globally
hope this works for you
EDIT just clarified a bit
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I have a JQuery-Code like this:
$.post("count_images.php",{}, function(data)
{
if (data != '')
{
alert(data);
}
else
{
//Error
}
});
It simply sends a request to count_images.php and returns a number like 23 for example. This works perfectly fine, but when i change it into this:
var number_images;
$.post("count_images.php",{}, function(data)
{
if (data != '')
{
number_images = data;
}
else
{
//Error
}
});
alert(number_images);
It does not work correctly. The alert-function always outputs an undefined. I simply want to save the result saved in data in a variable called number_images so i can keep on working with that. Thank you very much in advance.
The $.post() method is asynchronous, so when the second code snippet runs, the alert will be fired off before the AJAX POST returns with date, hence why number_images is undefined (as it hasn't been populated yet).
You can have the POST be executed synchronously by using $.ajax() and passing async: false and method: 'POST' flags. But this is not usually a good idea, as it defeats the entire purpose of AJAX (the A stands for asynchronous, after all).
Alternatively, either use the callback function (same as the first snippet) or attack other callbacks using the jQuery Promise API. For example
$.post("count_images.php")
.done(function(data)
{
if (data != '')
{
alert(data);
}
else
{
//Error
}
});
Keep in mind that $.post() is an asynchronous method and all that code is in a callback function, so when
alert(number_images);
is called, your callback function likely has not run yet because $.post() is still waiting for a response.
You need to put anything that uses number_images in the callback. It might be helpful to define another function like so:
var number_images;
var do_stuff_with_number_images = function() {
alert(number_images);
// any other code referencing number_images goes here
};
$.post("count_images.php",{}, function(data)
{
if (data != '')
{
number_images = data;
}
else
{
//Error
}
do_stuff_with_number_images();
});
alert(number_images);
var number_images,
data ='';
$.post("count_images.php",{}, function(data)
{
if (data != '')
{
number_images = data;
}
else
{
//Error
}
});
alert(number_images);
jQuery(document).ready(function(jQuery) {
function checkEmail(email){
jQuery.post('someroute.php',
{email:eamil},
function(data){
if(data==error){
return false;
}
);
return true;
}
jQuery('#myform').submit(function(){
// como code and at the momment this
var result true;
//then I check email
var email = ('#myemail').val();
result = checkEmail(email);
return result;
});
The problem is this, a checkEmail function, first return true, and then return value jQuery.post function. Why?
I checked and in submit, first return true, and if you stop submit then you release that post return the value. Post works fine, but I don't understand why function checkEmail does not wait until post returns the value and goes on until the end to return true.
Because the jQuery.post() function is an AJAX request, and the first A in AJAX stands for asynchronous. That's exactly what asynchronous is, it doesn't stop code execution while it waits for a response. It fires the request and then immediately moves on to any code after the line making the request, in this case your return true statement.
Like Anthony Grist said. .post is an asynchronous call which means it doesn't wait to finish.
I've looked up the .post method (http://api.jquery.com/jQuery.post/).
It's basicly a shortcut for .ajax. You're missing the fail method in here so I would say use the .ajax call.
var value = 1;
var handlerUrl = "someroute.php";
//Do the Ajax Call
jQuery.ajax(
{
url: handlerUrl,
data: { email:eamil },
type: 'POST',
success: function (data)
{
return true;
},
error: function (jxhr, msg, err)
{
return false;
}
});
#user1727336 : Hi! You might want to edit your code and add the missing } and });. Here's a fix:
// enter code here
jQuery(document).ready(function(jQuery) {
function checkEmail(email){
jQuery.post('someroute.php', {email:eamil},
function(data){
if(data==error){
return false;
}
});
return true;
}
});
Not sure if my question is subjective/objective but as a JavaScript newbie i'm encountering this problem quite a lot. So here I go.
I'm used to write C#, so my JavaScript structure looks like C#. And just that, that gives problems I think ;-)
Let's give a simple example where I met my problem again today:
MyLibrary.fn.InitAddEntityForm = function () {
$('a#btnAddEntity').click(function () {
//post data and receive object with guid and isPersisted boolean
var persistedObject = MyLibrary.fn.CheckAndSendAddEntityForm("name", "avatarurl.png");
console.log("test");
//check if persisted and go to next step
if (persistedObject.isPersisted) {
MyLibrary.fn.InitAddAnotherEntityForm(persistedObject.gdEntityId);
} else {
alert("Oops, something went wrong. Please call 911");
}
});
};
//////*****/////
//SOME FUNCTION THAT SENDS MY FORM AND RETURNS AN OBJECT WITH TRUE VALUE AND POSTED ENTITY ID
/////*****//////
MyLibrary.fn.CheckAndSendAddForm = function (txtName, ImageUrl) {
var postUrl = "/admin/add";
var persistedObject = new Object();
$.post(
postUrl,
{ Name: txtName, ImageUrl: txtImageUrl},
function (data) {
if (data.Status == 200) {
console.log("Post status:" + data.Message);
persistedObject.isPersisted = true;
persistedObject.gdEntityId = data.Data;
} else if (data.Status == 500) {
console.log("Failed to post entitiy");
} else {
console.log("Fault with Javascript");
}
}, "json"
);
return persistedObject;
};
Okay, thats it. Everything looks okay right? Browser says no.
I tried to debug it using firebug, looping over my code line by line, and that way the browser does what I want: Execute a new function to show the next panel in my wizard.
After placing a lot of Console.logs() in my code I figured out that this must be something about timing in JavaScript. In C# the code executes line by line, but apparently JavaScript doesn't.
By placing that Console.log("test") I noticed that "test" appeared in my console before "Post status: Success!".
So here's my question, how should I write my JavaScript code so I have control over the way the browser executes my code?
Should I really replace the code below to the end of my CheckAndSendAddEntityForm()?
//check if persisted and go to next step
if (persistedObject.isPersisted) {
MyLibrary.fn.InitAddAnotherEntityForm(persistedObject.gdEntityId);
} else {
alert("fout");
}
Is this how I have to write JavaScript: One big domino effect or am I just doing something wrong?
$.post is a shortcut for an AJAX call, AJAX is by definition asynchronous, which means it won't wait on a response before continuing processing. If you switch it to a regular AJAX() method, there is an async option you can set to false, which will make it behave as you are expecting.
Alternatively you can also define a function to execute on successful return of the AJAX request, in which you can call the next step in your process chain.
The AJAX call is asychronous; that means that the callback method exposes by $.post will be executed when the request completes, but your javascript will continue executing as soon as the invoke to $.post finishes. If you want to do something after the ajax call is done, you need to provide a callback method and do something else, ex:
MyLibrary.fn.CheckAndSendAddForm = function (txtName, ImageUrl, callback) {
var postUrl = "/admin/add";
var persistedObject = new Object();
$.post(
postUrl,
{ Name: txtName, ImageUrl: txtImageUrl},
function (data) {
if (data.Status == 200) {
console.log("Post status:" + data.Message);
persistedObject.isPersisted = true;
persistedObject.gdEntityId = data.Data;
} else if (data.Status == 500) {
console.log("Failed to post entitiy");
} else {
console.log("Fault with Javascript");
}
callback(); // This is where you return flow to your caller
}, "json"
);
};
Then you invoke like so:
var persistedObject = MyLibrary.fn.CheckAndSendAddEntityForm("name", "avatarurl.png", function()
{
console.log("test");
//check if persisted and go to next step
if (persistedObject.isPersisted) {
MyLibrary.fn.InitAddAnotherEntityForm(persistedObject .gdPronoId);
} else {
alert("Oops, something went wrong. Please call 911");
}
});
JavaScript is single-threaded. If you have asynchronous functionality, a simple boolean semaphore variable will help not to allow invocations of a function while some processes are running.
If you want to execute asynchronous tasks one by one (like a domino line), you will need to use callback functions.
What you're encountering is the "asynchronous" bit of AJAX. If you want to physically (as in the line line by line in the Javascript file) you can use the .success,.pipe or .done jQuery methods to add a callback to process the data further. Don't embed your callbacks if you can help it, or you will get a "domino effect" as you call it.
I have a form of which I catch the submit event. I have to wait for a $.post call in order to decide whether to submit it. I've tried this:
$('#my_form').submit(function(event){
var data = null;
$.post("/post/call").then(function(_data){
data = _data;
});
if ( $.isPlainObject(data) && data.status === 'ko' ) {
return false; // Do not submit the original form
} else {
// Submit the original form
}
});
But data results to be always null, also if _data is valorized, because $.post is an asynchrounous call. How can I wait for the $.post call to be completed?
EDIT: As wrote in the comments, I would like to avoid $.ajax({async: true}), because it freezes the page; is there any way to get the same effect without freezing the page?
You should have some sort of flag that says the form is to be submitted or not as well as that the ajax is processing. Then when the ajax call passes, call $('#my_form').submit() to send the form.
Loosely,
var validated = false;
$('#my_form').submit(function(event){
if (validated) {
return true;
}
$.post("/post/call").then(function(_data){
var data = _data;
if ( $.isPlainObject(data) && data.status === 'ko' ) {
// Do not submit the original form
} else {
validated = true;
$('#my_form').submit();
}
});
return false;
});
If you are using MVC / C#, and can use a Json request to access your web service, know the following.
$.getJSON
Is asynchronous
SOLUTION: $.ajax
Can be set to synchronous