Why is my jQuery wait cursor code not working? - javascript

I've got this jQuery in a page:
<script>
$(document).ready(function () {
$("#btnGetData").click(function () {
var _begdate = $("#datepickerFrom").val();
var _enddate = $("#datepickerTo").val();
var _unit = $("#unitName").text();
document.body.style.cursor = 'wait';
$.ajax({
type: 'GET',
url: '#Url.RouteUrl(routeName: "QuadrantData", routeValues: new { httpRoute = true, unit = "un", begdate = "bd", enddate = "ed" })'
.replace("un", encodeURIComponent(_unit))
.replace("bd", encodeURIComponent(_begdate))
.replace("ed", encodeURIComponent(_enddate)),
contentType: 'text/plain',
cache: false,
xhrFields: {
withCredentials: false
},
success: function (returneddata) {
$("body").html(returneddata);
},
error: function () {
console.log('hey, boo-boo!');
}
});
document.body.style.cursor = 'pointer';
});
});
</script>
Note that I try to create a wait cursor early on in the click handler:
document.body.style.cursor = 'wait';
...and then revert back to the default at the end:
document.body.style.cursor = 'pointer';
However, it doesn't work - the cursor never changes. The code does work (the ajax call completes successfully), but the cursor remains stonefaced, causing the user to wonder whether anything is happening.
What do I need to do yet to get the cursor to morph into a waiting attitude?

Because of the nature of the ajax calls (i.e. being async) the code executes the first line to change the cursor
document.body.style.cursor = 'wait';
then executes the ajax call (note: it does not wait for the response).
and then executes the last line:
document.body.style.cursor = 'pointer';
It all happens so fast, you probably don't notice.
At some point later, the ajax response is received and handled by either the success or fail callback handlers.
To change the cursor always after the ajax response is received (either success or failure), you need to add another callback called always - something along the lines of:
...
,
always: function () {
document.body.style.cursor = 'pointer';
});
...
Note, depending of the version of Jquery, this could be called a done() callback instead.
Check documentation here: http://api.jquery.com/jquery.ajax/
UPDATE
I updated the format to current practice and added the missing call...
$(document).ready(function() {
$("#btnGetData").click(function() {
//var _begdate = $("#datepickerFrom").val();
// var _enddate = $("#datepickerTo").val();
// var _unit = $("#unitName").text();
document.body.style.cursor = 'wait';
$.ajax({
type: 'GET',
url: 'http://stackoverflow.com/',
contentType: 'text/plain',
cache: false
})
.done(function() {
console.log('hey, success!');
})
.fail(function() {
console.log('hey, boo-boo!');
})
.always(function() {
console.log('hey, done!');
document.body.style.cursor = 'pointer';
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnGetData">Get it</button>

Try this:
<script>
$(document).ready(function () {
$("#btnGetData").click(function () {
var _begdate = $("#datepickerFrom").val();
var _enddate = $("#datepickerTo").val();
var _unit = $("#unitName").text();
document.body.style.cursor = 'wait';
$.ajax({
type: 'GET',
url: '#Url.RouteUrl(routeName: "QuadrantData", routeValues: new { httpRoute = true, unit = "un", begdate = "bd", enddate = "ed" })'
.replace("un", encodeURIComponent(_unit))
.replace("bd", encodeURIComponent(_begdate))
.replace("ed", encodeURIComponent(_enddate)),
contentType: 'text/plain',
cache: false,
xhrFields: {
withCredentials: false
}
}).done(function(returneddata){
$("body").html(returneddata);
}).fail(function(){
console.log('hey, boo-boo!');
}).always(function(){
document.body.style.cursor = 'pointer';
});
});
I've also "modernized" your jquery to use done(), fail() which are the newer standards. The always() handler will (maybe obviously) always run after the AJAX call returns.
I hand typed this, so I'm hoping the brackets all line up. I'm sure you'll get the gist.
By looking at this jQuery doc, you will see that success, error are deprecated.
Edit: I've created a working fiddle for you. Once you click the button, the fiddle simulates a 5 second AJAX call. One change is that I changed the style of html and body $('html,body').css('cursor','wait');

Related

Upon success response with data from Ajax call, process additional function as well

I am trying to call function upon successful response from ajax call.
Here both functions:
function waggle() {
var element = $(this);
var tmpClass = element.attr('class');
element.removeClass();
setTimeout(function() {
element.offsetWidth = element.offsetWidth;
element.addClass(tmpClass).addClass('start-now');
}, 10);
}
function auto_load(){
$.ajax({
type: 'POST',
data: {room_id:'$r_room_id',site_id:'$r_site_id'},
url: 'cart_counter.php',
success: function(data){
$('#cart_buble').html(data);
waggle();
}
});
}
This does update #cart_buble div as expected with the number in the cart however doesn't execute waggle function which is responsible for calling css transition effect.
Both functions are working fine seperately.
I think this variable is the problem here.
This kind of function declaration can change the data stored in this variable up to where the function is executed.
Try this way
function waggle() {
var element = $(...); // <--- Query your element instead of using `this`
var tmpClass = element.attr('class');
element.removeClass();
setTimeout(function() {
element.offsetWidth = element.offsetWidth;
element.addClass(tmpClass).addClass('start-now');
}, 10);
}
function auto_load(){
$.ajax({
type: 'POST',
data: {room_id:'$r_room_id',site_id:'$r_site_id'},
url: 'cart_counter.php',
success: function(data){
$('#cart_buble').html(data);
waggle();
}
});
}

Change cursor to wait before an Ajax petition is sent

I have the following JavaScript function, which is executed when a button is clicked:
function calculate(resource) {
document.getElementById('loading-label').innerHTML = 'Calculating...';
$.ajax({
url: resource,
type: 'GET',
async: false,
headers: {
'Content-Type': 'application/json'
},
beforeSend: function () {
document.body.style.cursor('wait');
},
complete: function () {
document.body.style.cursor('default');
}
}).done(function (data, textStatus, jqXHR) {
if (data == true) {
document.getElementById('loading-label').innerHTML = 'Done!';
document.getElementById('loading-label').style.color = 'green';
} else {
document.getElementById('loading-label').innerHTML = 'Error!';
document.getElementById('loading-label').style.color = 'red';
}
});
}
But it doesn't work as I want. Maybe because I'm not using beforeSend and complete callbacks properly.
As it can be seen, when the button is clicked, a label changes its content and I would like to change the cursor to waiting until the synchronous call is finished (and then return to default). How could I do that?
You can't when you make a non-async request.
Aside from your trivial error (you need to assign new values to cursor with =, it isn't a function).
Synchronous requests block the event loop (which is why they are deprecated). Since the event loop is blocked, the browser doesn't perform a repaint, and the cursor doesn't change.
Write asynchronous code instead.
function calculate(resource) {
document.getElementById('loading-label').innerHTML = 'Calculating...';
document.body.style.cursor = 'wait';
$.ajax({
url: resource,
}).done(function (data, textStatus, jqXHR) {
if (data == true) {
document.getElementById('loading-label').innerHTML = 'Done!';
document.getElementById('loading-label').style.color = 'green';
document.body.style.cursor = 'default';
} else {
document.getElementById('loading-label').innerHTML = 'Error!';
document.getElementById('loading-label').style.color = 'red';
document.body.style.cursor = 'default';
}
});
}

Ajax Uncaught TypeError: in simple function

In my code i am getting this error
Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
but when I remove
delay(function(){ ... }, 1000);
from my source file my code works perfectly I don't know what I am doing wrong with it or missing something that is really important to do, here is my full code
function checkurl(textname) {
$.ajax({
type: "POST",
url: "includes/modContent/checkurl.php",
data: "checkurl=" + textname,
dataType:'text', //or HTML, JSON, etc.
success: function(response){
//alert(response);
textname = response;
}
});
return textname;
}
$('input[name=txtPageName]').keyup(function() {
delay(function(){
$('input[name=txtSeoURL]').val(checkurl($(this).val()));
}, 1000);
});
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
The immediate issue, amongst others, is that you're changing the scope of this when you pass the callback to the setTimeout() handler.
To fix the issue you need to invert your logic so that you set the val() of the field when the AJAX completes instead of using a convoluted method of attempting to return data from an async function. Try this:
var timeout;
$('input[name="txtPageName]"').keyup(function() {
clearTimeout(timeout);
var textname = $(this).val();
setTimeout(function() {
$.ajax({
type: "POST",
url: "includes/modContent/checkurl.php",
data: { checkurl: textname },
dataType: 'text',
success: function(response) {
$('input[name=txtSeoURL]').val(response.trim());
}
});
}, 250);
});

AJAX sending multiple requests after button click

I just want one click to equal one submit in my jQuery code.
I've read quite a few posts on this same topic but I think mine is different. I do have a mouseleave and focusout event that I'm using to find errors in user input. Those functions feed down into the function that is submitting multiple times. The more times I hit mouseleave and focusout the more times my Ajax request is submitted. But I need mouseleave and focusout to continue to work and check the users input, that's why I'm not using one. Please see my code below, the function that I think is submitting multiple times is handleButtonClicksAfterError
function getCreditAmountToSend(modal){
console.log("getCreditAmountToSend");
var checkBox = $(modal).contents().find("#fresh-credit-checkbox");
checkBox.change(function(){
if($(checkBox).is(":checked")) {
var creditAmount = +(sessionStorage.getItem("creditAmount"));
sessionStorage.setItem('amountToSend', creditAmount);
}
});
var pendingCreditAmount = $(modal).contents().find("#pending_credit_amount");
pendingCreditAmount.on({
mouseleave: function(){
if(pendingCreditAmount.val() != ""){
adminForGetPendingCredit(modal);
}
},
focusout: function(){
if(pendingCreditAmount.val() != ""){
adminForGetPendingCredit(modal);
}
}
});
}
function adminForGetPendingCredit(modal){
console.log("adminForGetPendingCredit");
var checkBox = $(modal).contents().find("#fresh-credit-checkbox");
if(!$(checkBox).is(":checked")) {
var enteredAmount = +($(modal).contents().find("#pending_credit_amount").val());
var creditAmount = +(sessionStorage.getItem("creditAmount"));
sessionStorage.setItem('enteredAmount', enteredAmount);
doWeDisplayError(modal,creditAmount, enteredAmount);
}
}
function doWeDisplayError(modal,creditAmount, enteredAmount){
console.log("doWeDisplayError");
$(modal).contents().find("#fresh-credit-continue-shopping").prop("disabled", false);
$(modal).contents().find("#fresh-credit-checkout").prop("disabled", false);
if(creditAmount < enteredAmount){
$(modal).contents().find("#pending_credit_amount").val("");
$(modal).contents().find("#fresh-credit-continue-shopping").prop("disabled", true);
$(modal).contents().find("#fresh-credit-checkout").prop("disabled", true);
displayError();
}
else{
handleButtonClicksAfterError(modal, enteredAmount);
}
}
function handleButtonClicksAfterError(modal, enteredAmount){
// this is the problem!!!!!!!!!!!!!
console.log("handleButtonClicksAfterError");
sessionStorage.setItem('amountToSend', enteredAmount);
var continueButton = $(modal).contents().find("#fresh-credit-continue-shopping");
continueButton.click(function() {
modal.hide();
});
var checkoutButton = $(modal).contents().find("#fresh-credit-checkout");
checkoutButton.click(function() {
console.log("handleButtonClicksAfterError");
sendData();
});
}
function displayError(){
console.log("displayError");
$(function(){
$("#fresh-credit-iframe").contents().find("#pending_credit_amount").attr("placeholder", "Whoops, that was too much");
$("#fresh-credit-iframe").contents().find("#pending_credit_amount").attr({
class: "form-control form-control-red"
});
sessionStorage.removeItem('enteredAmount');
});
}
This is the function that actually POSTs the data
function sendData(){
var amountToSend = sessionStorage.getItem("amountToSend");
var products = $.parseJSON(sessionStorage.getItem("products"));
console.log("sendData");
console.log("This is the amount to send " + amountToSend);
$.ajax({
url: "/apps/proxy/return_draft_order",
data: {amountToSend, products},
type: "POST",
dataType: "json",
complete: function(data) {
window.location.href = data.responseText;
console.log("This is the URL from poll " + data.responseText );
return false;
},
});
}
It ended up being super simple.. I just needed the jQuery off method.. I attached it to the button before click and everything is peachy.. Looks like this:
checkoutButton.off().click(function(){});
off clears all the previous event handlers and then just proceeds with Click
Pretty cool, to read more check it out here
use async:false to prevent multiple request
$(document).off('click').on('click', function(){
$.ajax({
type:'POST',
url: ,
async:false,
cache: false,
data:{}
,
success: function(data){
},
error:function(data){
}
});
});

Keep setTimeout function running after browser becomes idle

The following code is used for keeping track of updates from a database.
Problem is it will stop running after some time (probably when the browser becomes idle).
$(function() {
function Update() {
var postData = "";
$.ajax({
url: 'functions/ajax_api.php?dashboarddata',
type : 'post',
data: postData,
success: function(resp) {
$('#entradasmas7').html($('#entradasmas7' , resp).html());
$('#entradasmenos7').html($('#entradasmenos7' , resp).html());
// Call Update again after 30 seconds.
setTimeout(function() { Update(); }, 30000);
}
});
}
// Call postData the first time to start it off.
Update();
});
How can I make it run continually regardless of browser state, or call it back when the window becomes active?
In case of error it will not restart the timer, so there are 2 solution:
A.: add error handler and put the setTimeout(function() { Update(); }, 30000); code into the handler, because in case of error nothing restarts the timer.
disadvantages: callings are not exact 30sec later in case of long time response
$(function() {
function Update() {
var postData = "";
$.ajax({
url: 'functions/ajax_api.php?dashboarddata',
type : 'post',
data: postData,
success: function(resp) {
$('#entradasmas7').html($('#entradasmas7' , resp).html());
$('#entradasmenos7').html($('#entradasmenos7' , resp).html());
// Call Update again after 30 seconds.
setTimeout(function() { Update(); }, 30000);
},
error: function() {
setTimeout(function() { Update(); }, 30000);
}
});
}
// Call postData the first time to start it off.
Update();
});
B.: use setInterval instead of setTimer: but you have to schedule only onece, and you have to abort the previous ajax call if the next tick is coming:
$(function() {
var xhr = null;
function Update() {
var postData = "";
if(xhr!=null) { xhr.abort(); } // avoid paralell call of ajax_api.php, so we stop the previous one
xhr = $.ajax({
url: 'functions/ajax_api.php?dashboarddata',
type : 'post',
data: postData,
success: function(resp) {
$('#entradasmas7').html($('#entradasmas7' , resp).html());
$('#entradasmenos7').html($('#entradasmenos7' , resp).html());
}
});
}
// Call postData the first time to start it off.
Update();
setInterval(function() { Update(); }, 30000);
});

Categories

Resources