How to avoid ajax async when using jQuery events - javascript

I have an input field with ajax call (filling some other input fields) on blur and buttons with click events (some of the click events set input fields to an empty string).
For example,
$("#input_field1").on('blur', function () {
$.ajax({
//async:false,
method: "GET",
url: "my_ajax.php",
cache: false,
dataType: "json",
data: { data1: $("#input_field1").val()},
success: function(result){
$("#some_other_input").val(result.data2);
}
})
});
$("#button1").on('click', function () {
$("#input_field1").attr("readonly", true);
var form = $("#my_form");
form.validate().resetForm();
form[0].reset();//form contains #some_other_input
});
When that input field is focused and then user clicks on any button, blur event is triggered and of course, appropriate click event after it.
If I don't use async:false, ajax will fill those input fields after click event is processed and other inputs will be filled instead of being empty.
Reading about how async:false should be avoided always, I need a way for my click events to wait until ajax is done, if there is an ajax call at that moment.

You need a concurrency check for your cases. On your blur action; check and set a value to prevent reentering the other calls.
Also during an ajax request, you need to prevent clicking the buttons.
One more thing, what if just after bluring your input field, user re-focuses and re-focusouts your input? In this case, your action will be triggered twice.
As a result, you need to handle concurrency. There are also some javascript libraries to handle concurrency, you can either use them or handle by your own.
Anyway to handle your case, here is a sample code:
let hasCall = false;
$("#input_field1").on('blur', function () {
if(hasCall){
return; //there is an active call...
}else{
hasCall = true;
$("#button1").prop('disabled', true);//prevent clicking on button
}
$.ajax({
//async:false,
method: "GET",
url: "my_ajax.php",
cache: false,
dataType: "json",
data: { data1: $("#input_field1").val()},
success: function(result){
$("#some_other_input").val(result.data2);
}
}).always(()=>{
//reset the state:
hasCall=false;
$("#button1").prop('disabled', false);
});
});
$("#button1").on('click', function () {
$("#input_field1").attr("readonly", true);
var form = $("#my_form");
form.validate().resetForm();
form[0].reset();//form contains #some_other_input
});

Related

jQuery Click Handler with Called Ajax Sub-Method has a strange delay on $(this).prop('disabled', true) [duplicate]

This question already has answers here:
updated UI not showing before sync ajax call
(2 answers)
Closed 3 years ago.
I have a strange situation where the following Click-Handler (via one() to prevent double-clicks) has a called Ajax method from the inside. The first thing it's supposed to do is to disable my button.
Normally, if I don't have any Ajax inside and just have a simple click handler, this works and disables the button immediately:
$('#button').one('click', function (event) {
$(this).prop('disabled', true);
});
But if I have the following, with a called sub-method which involves Ajax, I notice that the 1st statement (Disable Button) does not occur until the sub-method is complete. But why? The button should get disabled immeditely as the first statement, regardless of how long the Ajax takes to complete.
$('#submitButton').one('click', function (event) {
$(this).prop('disabled', true); // Doesn't get disabled until AFTER submitSurvey()
submitSurvey(); // Call some method that does Ajax
});
function submitSurvey() {
$.ajax({
url: 'surveyProcess',
type: 'post',
processData: false,
contentType: false,
data: formData,
async: false, /* Note async = false, so nothing asynchronous here either */
success: function() {
//...
}
What could be going on here? I just need to disable the button immediately, without any delay.
You can use beforeSend() event for the same use
$('#submitButton').on('click', function (event) {
$.ajax({
url: 'surveyProcess',
type: 'post',
processData: false,
contentType: false,
data: formData,
async: false, /* Note async = false, so nothing asynchronous here either */
beforeSend: function(){
$(this).prop('disabled', true);
},
success: function() {
//...
}
});
});

Fullcalendar updateEvent doesn't rerender

I want to add events to my DB via fullcalendar. So I want to add an event and set its id to the id it gets in my DB.
function addCalEvent(event) {
var jEvent = {};
jEvent['startTime'] = moment(event.start).unix();
jEvent['worker']="GUZ"
jEvent['title']=event.title;
if (event.end) {
jEvent['endTime'] = moment(event.end).unix();
}
$.ajax({
url: 'dux.html',
type: 'POST',
data: {
type: 'addNewEvents',
event: jEvent,
REQUEST_TOKEN: "REQUEST_TOKEN>",
},
datatype: 'json',
success: function(data) {
event.id=data;
event.title="NEW";
$('#calendar').fullCalendar('updateEvent', event);
},
});
}
The ajax retrieves the id of the added event and the id and title do get changed, but the 'updateEvent' method doesn't seem to be called, because there is no change to the rendered events title or id.
Ok,
apperently if you make a asynchronous ajax call the order in which commands are executed isn't the order you write it.
I need to add async: false to make this work.
You can manually call rerender events with $('#calendar').fullCalendar( ‘rerenderEvents’ )
Link to docs here

unbind event handlers while ajax in progress

I have a text field with keypress event handler jsfiddle. And when I type something in this field and press "Enter" 2 times, 2 requests will be send. I want to turn off all events, while ajax request in progress. One option is to call .off() function before ajax call, and then bind event handler again. Any other options?
use the callback handlers from your ajax call and a boolean used as flag. By setting the ajaxLoading boolean to false in the "always" callback, you can be sure that other, future requests can be made independent from whether the current ajax call throws an error or not.
var ajaxLoading = false;
if(!ajaxloading){
ajaxloading=true;
$.ajax({
url: 'your url',
type: 'GET',
dataType: 'JSON'
})
.done(function(data) {
console.log("success");
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
ajaxloading=false;
});
}
I use 2 boolean flags, like:
var is_requesting = false, should_request = false;
function onkeydown() {
if (is_requesting) {
should_request = true;
return;
}
is_requesting = true;
$.ajax({}, function () {
is_requesting = false;
if (should_request) {
onkeydown();
}
});
}
Is there a good reason for you not to use the jQuery .off() function?
If so then you could simply disable the control prior to making the ajax request and re-enable it once the request is complete. This would also stop the user from thinking he/she could change the result by changing the text value during the request.
//Disable the input
$('#myresult').prop('disabled', true);
$('#myresult').append('<br>'+$(this).val());
$.ajax({
type: "POST",
beforeSend: function() {},
complete: function() {
//Re-Enable the input
$('#myresult').prop('disabled', false);
},
url: "/echo/json/",
data: { delay : 3 },
success: function(){},
error: function() {},
dataType: 'json'
});

JQuery attempt to change window.location incorrectly truncating query parameters

I'm experimenting with JQuery for fun and I've run into a bit of a brick wall. I'm attempting to write a login page and my thought was to have a form on a jsp where a user would enter a login id and password and click a submit button. This then gets caught by a JQuery method that then makes an AJAX call to the back-end. The "success" method should then set the window object's location to a new URL indicated by the value returned from the Ajax call. FYI: I'm a back-end guy and I have that portion covered. My problem is that although I call the back-end and get the data I require. I then attempt to set a new window location with a URL that contains a single query parameter (to allow the app to know who the user is), which almost works as I get to the base URL but with no query parameters (though there is a '?' on the end of the base URL)
Here's my JQuery code:
</script>
$(document).ready(function(){
submit( function() {
var id = $("#login_id").val();
var pwd = $("#password").val();
var uri = "`http://localhost:8080/SW_Server/rest/admin/login`";
$.ajax({
async: false,
url: uri,
type: 'GET',
dataType: "json",
success: function(data) {
var session = data.session;
newLoc = data.redirect+"?"+data.session
// Prevent the form's default submission.
preventDefault();
// Prevent event from bubbling up DOM tree, prohibiting delegation
event.stopPropagation();
window.location.replace(encodeURIComponent(newLoc));
},
error: function(jqHHR, textStatus, errorThrown) {
alert("textStatus: "+textStatus+"\nerror: "+errorThrown);
// Prevent the form's default submission.
event.preventDefault();
// Prevent event from bubbling up DOM tree, prohibiting delegation
event.stopPropagation();
}
});
});
</script>
When I execute this, my back end currently returns data.redirect=http://localhost:8080/test.jsp and data.session=session_id=3, which I see in an alert (hooray for me), but then when window.location.replace(newLoc) is called it goes to http://localhost:8080/test.jsp? with no query parameter. I've been banging my head all day. What can I do to get the query param correctly picked up by the new page?
Regards,
Tim
Try to assign the value to location instead
window.location = data.redirect;
did you try some of this:
$(document).ready(function(){
$("#loginForm").submit( function(event) {
var id = $("#login_id").val();
var pwd = $("#password").val();
var uri = "http://localhost:8080/SW_Server/rest/admin/login";
alert("uri: "+uri);
$.ajax({
async: false,
url: uri,
type: 'POST',
dataType: "json",
data: { "id":id, "pwd":pwd },
success: function(data) {
$('#loginForm').attr('action',data.redirect);
$('#loginForm').submit();
},
error: function(jqHHR, textStatus, errorThrown) {
alert("textStatus: "+textStatus+"\nerror: "+errorThrown);
}
});
// Prevent the form's default submission.
event.preventDefault();
// Prevent event from bubbling up DOM tree, prohibiting delegation
event.stopPropagation();
//and also
return false;
});
});

jQuery Allow only one click before .ajax()

I am trying to allow a button to be clicked only once and then some data be submitted via ajax. The problem I am facing is that a user can click 50x and the data is POST submitted each time ?
jQuery("#id").unbind('click');
jQuery.ajax({
type: "POST",
url: ajax_url,
data: ajax_data,
cache: false,
success: function (html) {
location.reload(true);
}
});
How can I ensure that if a user clicks #ID 100x - that the data is only submitted once ? And then #ID is re-enabled ?
You could use the .one() function in jQuery.
jQuery("#id").one('click', function()
{
jQuery.ajax({
type: "POST",
url: ajax_url,
data: ajax_data,
cache: false,
success: function (html) {
location.reload(true);
}
});
});
Bear in mind this will completely remove the click event, even if you have an error with your ajax, you still won't able to click it again.
just disable the button
$("#id").attr("disabled", "disabled")
and then in the success function enable it
$("#id").removeAttr("disabled")
Easiest way would be to use a flag which gets reset when the success is fired:
if(clicked == False){
clicked = True;
jQuery("#id").unbind('click');
jQuery.ajax({
type: "POST",
url: ajax_url,
data: ajax_data,
cache: false,
success: function (html) {
location.reload(true);
clicked = False;
},
error: function () {
alert("Error happened");
clicked = False;
}
});
}
You can disable to control, or use one of the many modal libraries to show the spinning wheel
see this Jquery modal dialog question on SO
You could disable the button on click event and enable it back when ajax request is completed.
In your click event you could disable the button and then re-enable the button in the success function of the ajax event.
Another option would be to set a parameter on the element that is being clicked to indicate the button was clicked and then check to see if it is set if it is don't send the ajax request if not then do send it. Once the ajax is done you can unset the parameter again to allow it to be run.
try this:
$(document).ajaxStart({ function() {
$('#submit_button').click(function(){
return false;
});
});
where: #submit_button is id of the element U want to disable
that code will disable clicking on the submit button

Categories