How do I control form submission from within ajax callback? - javascript

I originally had the return true/false in my ajax callback, and realized it's probably not in the right context to be called, so I rewrote my function as follows, but it is still not working. Is the submit variable not carrying through from the callback function either? The confirmation (if .btn-danger) is working, but not just if you hit submit and confirmation is not needed)
$('#form').submit(function(e){
var submit = false;
if($('.btn-danger').length){
submit = true;
} else {
$.ajax({
url: base_path+"ajax/myajaxfile",
type: "post",
data: {
data1 : $("#amount").val(),
data2 : $("option:selected").val()
},
dataType: "json",
success: function(data) {
if (data.needconfirmation === 'true'){
$('#edit-submit').val("Confirm");
$('#edit-submit').removeClass("btn-primary");
$('#edit-submit').addClass("btn-danger");
$('#payment-form').after('<span class="warning"> Do you really wanna?</span>');
} else {
submit = true;
}
},
error: function(data) {
alert("an error has occurred");
}
});
}
if (submit){
return true;
} else {
return false;
}
});

I think your issue is that ajax calls are asynchronous by default - so the return value of the function is being evaluated before the success function is ever called, and therefore the submit variable is still false.
You need to either make the ajax call synchronous:
async: false
or probably better would be to restructure it.

One of the most confusing aspects of doing AJAX for the first time is Asynchronous part. With normal Javascript (well, normal jQuery at least), you handle a submit like so:
$('#form').submit(function(e){
var submit = /*Figure out if it was a success or not*/;
if (submit){
return true;
} else {
return false;
}
});
An event triggers a submission, you figure out whether or not it's valid, and then you either proceed or you don't.
With an AJAX submission though that "Figure out if it was a success" step happens outside the normal flow of things. This means that what you want to do is ALWAYS return false; you don't know whether to proceed yet, so don't proceed. Your AJAX callback (the "success:" function in your AJAX call's options) is whether the "figure out" code goes, and your's currently has the right idea with "success = true" ... except that by the time it resolves, your original submit function will already be over (you'll have returned false to it).
So, what you then need to do is modify your success handler to do ... whatever it is that normally would happen when you submit. This might be as simple as form.submit() of a hidden form, or it might be more complex; I don't know your app. Hopefully this gives you the basic idea though.

$.ajax is asynchronous, so the rest of your code continues on before the success callback happens, so it setting submit = true doesn't affect the check at the end of your function.
The confirmation (if .btn-danger) is working, but not just if you hit submit and confirmation is not needed
How do you know if confirmation is needed or not? You may want to add a check for that where you check for .btn-danger.
Also, you can clean up the last bit of your code by just doing
return submit;

Related

Javascript preventing submit based on ajax response

I can't figure out why this code will not prevent a submit. All html is linked properly. All alerts display as expected. It doesn't seem as though I am losing scope on the event. Any suggestions, fixes or explanations would be awesome!
//Alert the potential customer if the email entered already exists.
function emailUniqueness() {
// When the Submit Button is clicked, then execute the following function...
$('#form').submit(function(event) {
//Remove error messages if they exist
$("#emailNotUniqueErr").empty();
$("#emailNotUniqueErr").removeClass('alert alert-warning');
//Make the call to servlet method
$.ajax({
url: 'http://localhost:8080/ShoppingCart/ajax.do',
success: function(response) {
searchForEmail(response, event);
}
});
//event.preventDefault(); works when placed here but is pointless.
});
}
function searchForEmail(response, event) {
//alert returns type "submit"
alert(event.type);
var emailEntry = $("#email").val();
var emailExists = false;
$.each(response, function(index, item) {
if(emailEntry == item.email) {
//Set to true when a match is found
emailExists = true;
//Exit the .each loop
return false;
}
});
//alert returns appropriate true or false for input entry
alert(emailExists);
if(emailExists) {
//still is type submit
alert(event.type);
//Properly print the warning if email exists
$("#emailNotUniqueErr").addClass('alert alert-warning col-sm-offset-2');
$('×').appendTo("#emailNotUniqueErr");
$('<strong>Warning! Account already exists. One account per Email.</strong>').appendTo("#emailNotUniqueErr");
//does not prevent submit???
event.preventDefault();
} else {
//No match found allow submit, remove errors
$("#emailNotUniqueErr").empty();
$("#emailNotUniqueErr").removeClass('alert alert-warning');
return true;
}
}
ajax call is asynchronous. Therefore the line searchForEmail(response, event); is executed with some delay (when the response comes for the request). When it is executed the form is already submitted. The order of execution is given below.
Function emailUniqueness() is called and execution of the function starts
ajax request is sent scheduling the callback to be executed after the response comes
Function emailUniqueness() function execution ends
Form submission
Response for the ajax request comes, callback executed, searchForEmail(response, event); is called
event.preventDefault() is called (this is called after the form is submitted)
You have to call the method event.preventDefault(); inside emailUniqueness() function which changes the order to the following.
Function emailUniqueness() is called and execution of the function starts
ajax request is sent scheduling the callback to be executed after the response comes
event.preventDefault() is called (this prevents form submission)
Function emailUniqueness() function execution ends
Response for the ajax request comes, callback executed, searchForEmail(response, event) is called
As a solution,
prevent the form submission inside emailUniqueness function
submit the form with $('#form').submit() inside searchForEmail function.

Form not submitting even no errors and OK response

I'm stuck with returning.
I need that if response is "ok", my form would be submitted else document wouldn't reload.
I've tried like that:
$(window).load(function(){
$('.check-connection').click(function(){
u = {};
u["host"] = $('[name="host"]').val();
u["db_user"] = $('[name="db_user"]').val();
u["db_pass"] = $('[name="db_pass"]').val();
u["db_name"] = $('[name="db_name"]').val();
$.post('check-connection.php',{secure:true,data:u}).done(function(r){
if(r == "ok"){
/*
here problems even returns ok
alert(r); - gives answer ok if trying to check..
*/
return true;
} else {
alert(r);
return false;
}
});
return false;
});
});
Any ideas? offers?
Probably you might want to remove the last return false; because it is returning before the ajax completes.
Let it return when the .done() handler is executed.
You can not return a boolean from within the ajax done function and expect it to be passed back to the click handler. The ajax is asynchronous and so the click handler will complete execution before the ajax response is received.
The logic should be: call the ajax on a button click (not form submit), then submit the form from within the ajax success handler, else don't do anything.

Trying to validate results after doing an ajax call

Alright so i have form validation function.the function runs through form validation functions that returns false if the field isn't valid.
The problem is when it get to the function that uses ajax to check if the field is valid.
for some reason its seems that it doesn't "wait" for ajax to return and returns false automatically.
is there a way around this?
Here is the code:
function form_validation(){
if (!NewValidationForm('pcode', 'Please fill in all the fields'))
return false;
if (!NewValidationForm('fname', 'Please fill in all the fields'))
return false;
if(!validate_coupon()){
alert("bad!!");
return false;
}
return true;
}
function validate_coupon(){
var url = $j("#site_url").val() + 'ajax_functions.php';
var coupon = $j("#pcode").val();
var result_status = false; // seem its jumps from here to:
$j.ajax({
type: "POST",
url: url,
data: { ajax: 'ajax', coupon: coupon}
}).success(function(insertID){
var obj = $j.parseJSON(insertID);
if(obj.status == 1){
result_status = true;
}
});
// straight over here
if(result_status == true){
return true;
}
}
Usually in this situation I do something like this in $(document).ready():
$('form').submit(function (evt) {
if (!$(this).attr('data-submitted')) {
evt.preventDefault();
$(this).attr('data-submitted', 'true');
// call your form validation code here that fires the ajax request
return false;
}
return true;
});
Then, in your $.ajax callback, when your validation completes, call $('form').submit(). This effectively uses an attribute on the form as a flag for whether the state of the validation request. When the user first submits the form, the flag gets set and the validation process begins. When the validation completes, the form's submit event is triggered, and since the flag is set, this time the form gets submitted like normal.
If this approach works for you, you'll probably want to add a little polish. For example, you'll probably want to disable the submit button before calling $.ajax and enable it again if the validation fails. You'll also probably want to remove the data-submitted attribute from the form if the validation fails, since the user might submit the form a second time and you presumably want to perform another validation in that case.

jQuery: Submit a form only if no AJAX is currently running on the page

When the city input field is blurred I get somnething via an ajax request and set that as the value of a hidden field in the same form that the city field resides in.
$('input#city').on('blur', function() {
$.ajax({
url: 'get/something?param=val',
success: function(response) {
$('input:hidden[name="something"]').val(response);
}
});
});
If the user submits the form immediately after blurring off the city field sometimes due to latency the hidden field is not populated because the SQL on the other end is taking too long.
The form that both these fields are in is also submitted via ajax:
$('form#find-users').on('submit', function() {
if(NO_AJAX_CURRENTLY_RUNNING_ON_PAGE) {
// do stuff
}
});
How to detect if no ajax is running on the page? This will ensure that the city ajax was completed and the hidden field populated before the form is processed.
EDIT
Actually it won't, it will only prevent the form from being submitted. But if I can detect that then I can use a setInterval and keep trying to run that code until it runs because ajax is complete. Ideally there will be something in jQuery that waits until other ajax is complete and then submits.
Use jQuery's Ajax Events. As long as all of your Ajax calls are generated using jQuery, you have a way of knowing if any Ajax calls are outstanding.
$(document).ready(function() {
var ajaxBusy = false;
$(document).ajaxStart( function() {
ajaxBusy = true;
}).ajaxStop( function() {
ajaxBusy = false;
});
});
Edit:
So that answers your direct question about "How do I know if there is any Ajax call running."
Alternatively, you could disable the form's submit buttons when run your blur handler, and then re-enable it when you're done.
$('input#city').on('blur', function() {
var submit = $(this).closest('form').find(':submit:enabled');
submit.prop('disabled', true);
$.ajax('get/something?param=val').done(function(response) {
$('input:hidden[name="something"]').val(response);
}).always(function() {
submit.prop('disabled', false);
});
});
Edit 2:
So now we're at the point where we would like to delay the form submission until all current Ajax calls have completed. We let people click on the submit button, but if there are pending Ajax calls we don't do anything right away.
We can use a Deferred object to help us with this.
$(document).ready(function() {
var ajaxDefer = $.Deferred().resolve();
$(document).ajaxStart( function() {
ajaxDefer = $.Deferred();
}).ajaxStop( function() {
ajaxDefer.resolve();
});
$('form#find-users').on('submit', function() {
ajaxDefer.always(function() {
// Code here will always be executed as soon as there are no
// Ajax calls running.
// this points to the deferred object (ajaxDefer), so use the closure
// to carry over any variables you need.
});
});
});
When we're just starting out, we set up our ajaxDefer object in a resolved state. That means any functions attached using .always() will execute immediately.
When the first Ajax call starts, we replace the old ajaxDefer object with a new one that has not been resolved. Any new functions attached using ajaxDefer.always() will be deferred until later.
When the last Ajax call completes, we call ajaxDefer.resolve(), which causes any unexecuted deferred functions to execute. Now we're back to our initial state, where any newly-attached functions will execute immediately.
When somebody tries to submit the form, create an anonymous function that does the work and attach it to ajaxDefer. It will get executed when appropriate, depending on if there are any outstanding Ajax requests or not. Be mindful of your closures.
Use this to check if AJAX calls are currently in-progress using JQuery:
if ($.active == 0) {
...
}
you can put a variable in the global namespace, perhaps named ajaxLock and toggle it on when AJAX starts and off when the response comes. Then check it before allowing submit.
something like
var ajaxLock = 1;
$('input#city').on('blur', function() {
$.ajax({
url: 'get/something?param=val',
success: function(response) {
$('input:hidden[name="something"]').val(response);
ajaxLock = 0;
}
});
});
Use a lock variable like you suggested:
$('input#city').on('blur', function() {
window.AJAX_CURRENTLY_RUNNING_ON_PAGE = true;
$.ajax({
url: 'get/something?param=val',
success: function(response) {
$('input:hidden[name="something"]').val(response);
},
complete: function() { window.AJAX_CURRENTLY_RUNNING_ON_PAGE = false; }
});
});
$('form#find-users').on('submit', function() {
if(window.AJAX_CURRENTLY_RUNNING_ON_PAGE) {
return;
}
//dostuff
});
What i could have done on this circumstances is to use plugin like block ui or disable the form submit button,the reason is you need to be interactive in your design,you may well able to lock the form submission,but its better to give a message or have a modal gray out

how to set and return a variable inside JavaScript function?

see the example first then you can understand my question.
var x;
function checkTime() {
$.ajax({
type: 'GET',
url: 'http://www.example.com/time.php',
data: test,
dataType:'json',
success: function (data) {
if (data == 0){
x = 'true';
} else if (data == 1){
x = 'false';
}
}
});
}
checkTime();
alert (x);
the alert will be undefined
I need to set x inside the checkTime functions and grab it outside the function
even if i do :
var x = checkTime();
alert (x);
i still get undefined
also i only need to check for true or false, maybe there is another way to do things. I also tried:
...
if (data == 0){
return true;
} else if (data == 1){
return false;
}
...
but i don't know how to check for that.
basically i need to so something like :
if (x == 1){ // if(x == true)
//do something
}
any ideas?
thanks
This happens because the default behaviour of .ajax() is asynchronous. x will not have been set by the time your alert() fires. You either need to set the .ajax() with aync=false or pass in a callback function to call when your Ajax request has completed, e.g.
function checkTime(callback) {
$.ajax({
type: 'GET',
url: 'http://www.example.com/time.php',
data: test,
dataType:'json',
success: function (data) {
var x = '';
if (data == 0){
x = 'true';
} else if (data == 1){
x = 'false';
}
// Call the callback function with 'x'
callback.call(null, x);
}
});
}
And then use it like follows:
checkTime(function (x) {
alert(x);
});
It happens because AJAX is asynchronous. When your code reaches alert, the success function of AJAX request does not executed yet. You can try to set ajax request to async:false, or make alert inside of success function.
You cannot directly access the return value of the function defined for the "success"; first you should know that two functions are involved here: checkTime, and the unnamed event handler function for the success event of the ajax call. You want to retrieve a value out of that unnamed event handler function; that function is however not called directly from checkTime, but when the AJAX request returns (it's event-driven programming: the function (data) {...} is executed when the event AJAX call succeeded happens).
In your example, the alert you call after executing checkTime will usually be called before the AJAX request is finished; this is because the AJAX request happens asynchronously, and therefore the event that the call succeeded need not have happened yet. If you always want to wait for the answer to the request, you can disable the asynchronicity of the AJAX call (async:false); but maybe you can also do the distinction what you want to do directly in the event handler instead of outside. That would be the way to go for if you want to follow event-driven programming paradigm.
If you want to continue doing something else while the request is running, your options would also include e.g. using some other (e.g. global) variable for the "return value" of the success function AJAX call (and possibly a second for indicating whether the call is finished), and checking periodically if it has been set yet (but that would not follow the event-driven programming paradigm, and might be considered bad practice since it unnecessary frequent polling of a variable is needed).
It happens because checkTime() returns immediately, before the success function is executed. The success function doesn't execute until after the ajax call is complete, so x is not set yet when you try to use it.
Depending on what you are trying to accomplish, you could put the alert inside the success callback.

Categories

Resources