AJAX async:true breaks site on mobile browsers - javascript

I am using this function to return search results via AJAX. However, it kills mobile browsers on search. It works if I set it to 'async:false' but this means that I can't have a loading icon.
I cant find anything online to indicate why this would not be working on mobile, when it works fine on desktop.
Any ideas?
(function($) {
$(document).ready(function() {
$("#filter").on('keyup input', function() {
delay(function() {
var input = $('#filter');
var query = input.val();
var content = $('#content')
$.ajax({
type: 'post',
url: myajax.ajaxurl,
async: true,
data: {
action: 'load_search_results',
query: query
},
beforeSend: function() {
input.prop('disabled', true);
content.addClass('loading');
},
success: function(response) {
input.prop('disabled', false);
content.removeClass('loading');
content.html(response);
myPluginsInit();
}
});
return false;
}, 700);
});
});
})(jQuery);

I was able to solve this problem by adding a separate 'loader' div with an ID of loader to my page, and add the loading class to this instead. The code now looks like this:
(function($) {
$(document).ready(function() {
$("#filter").on('keyup input', function(){
delay(function(){
var input = $('#filter');
var query = input.val();
var content = $('#content')
$.ajax({
type : 'post',
url : myajax.ajaxurl,
async: true,
data : {
action : 'load_search_results',
query : query
},
beforeSend: function() {
input.prop('disabled', true);
$('#loader').addClass('loading');
},
success : function( response ) {
input.prop('disabled', false);
$('#loader').removeClass('loading');
content.html( response );
myPluginsInit();
}
});
return false;
}, 700 );
});
});
})( jQuery );

You're problem is still in your keyup input handler. I'm not sure where the function delay is declared (I'm assuming it's some wrapper around setTimeout). However it doesn't really matter.
The issue is that the handler fires for every input and keyup event. The "delay" is inside that. All the "delay" is doing is "waiting" before it makes the ajax call but an ajax call is still being created for every keyup and input event.
This means that a lot of ajax calls are being created and on a mobile platform that's a problem. I'm not exactly certain when (or how often) you need to make the call to the server but to see what I'm talking about just add the line I've included below:
(function($) {
$(document).ready(function() {
$("#filter").on('keyup input', function() {
console.log('handling keyup or input') // add this line and watch them stack up
delay(function() {
var input = $('#filter');
var query = input.val();
var content = $('#content')
$.ajax({
type: 'post',
url: myajax.ajaxurl,
async: true,
data: {
action: 'load_search_results',
query: query
},
beforeSend: function() {
input.prop('disabled', true);
content.addClass('loading');
},
success: function(response) {
input.prop('disabled', false);
content.removeClass('loading');
content.html(response);
myPluginsInit();
}
});
return false;
}, 700);
});
});
})(jQuery);

Related

Firebug behavior when selecting an item from dropdown-list

I have a dropdownlist which when user selects an item from it, it renders the partial with relevant data. But if user changes the selection of ddl then the previously rendered content should be replaced with the current content.
Following is the code
Script
<script>
var prev;
$(document).on('focus', '.class03', function () {
prev = $(this).val();
}).on('change', '.class03', function () {
if (prev != "") {
$('.cmpCls').last().remove();
alert(prev);
$.ajax({
url: '#Url.Action("ComponentDts", "InquiryOrder")', // dont hard code your url's
type: "GET",
data: { DesignCdId: $(this).val() }, // pass the selected value
success: function (data) {
$('#cmpDts').append(data);
}
});
}
else {
$.ajax({
url: '#Url.Action("ComponentDts", "InquiryOrder")', // dont hard code your url's
type: "GET",
data: { DesignCdId: $(this).val() }, // pass the selected value
success: function (data) {
$('#cmpDts').append(data);
}
});
}
});
</script>
Div to append rendered Partial View
<div id="cmpDts">
</div>
Here what confuses me is when i use firebug, the script works fine replacing the previously rendered content in 'cmpDts' div when user changes the selection of dropdownlist.
But when i run the application without firebug and when user changes the selection of ddl, instead of replacing the previous content in div, it keeps on adding to the div without removing previous content.
I think without firebug, everytime it comes to else part no matter prev has a value or not. I could recognize it beacause alert not get fired without firebug here. Im confused with this behavior. All help appreciated. Thanks!
Edit: How i got that worked(I know this might not be the correct approach but with the restricted time i had to stick with this)
<script>
var prev;
$(document).on('focus', '.class03', function () {
prev = $(this).val();
}).on('change', '.class03', function () {
if (prev != "") {
//$('.cmpCls').last().remove();
alert("If");
$.ajax({
url: '#Url.Action("ComponentDts", "InquiryOrder")', // dont hard code your url's
type: "GET",
data: { DesignCdId: $(this).val() }, // pass the selected value
success: function (data) {
$('.cmpCls').last().replaceWith(data);
}
});
}
else {
alert("Else");
$.ajax({
url: '#Url.Action("ComponentDts", "InquiryOrder")', // dont hard code your url's
type: "GET",
data: { DesignCdId: $(this).val() }, // pass the selected value
success: function (data) {
$(".class03 option[value='']").remove() ;
$('#cmpDts').append(data);
}
});
}
});
</script>
You first of all need to wait for your document to be ready by using:
$(document).ready(function(){
});
Now, you want to check if something in .class03 changed.
$(document).ready(function(){
var prev;
$(".class03").focus(function(){ prev = $(this).val(); });
$(".class03").change(function(){
if (prev !== "") { $('.cmpCls').last().remove(); }
alert(prev);
$.ajax({
url: '#Url.Action("ComponentDts", "InquiryOrder")', // dont hard code your url's
type: "GET",
data: { DesignCdId: $(this).val() }, // pass the selected value
success: function (data) {
$('#cmpDts').append(data);
}
});
});
});
Try this.
Edit: removed double code

JQuery prevent links working whilst ajax is loading

I have a firework detonation system which uses JQuery to connect to a PHP script via AJAX to detonate the fireworks. The only problem is that if you click one launch button straight after another, there is a possibility of setting off more fireworks than you want.
I need a way to disable all other links on the page until the ajax has finished and received a response. I have tried:
//Prevent clicks
$("body").find("a").click(function (e) { e.preventDefault(); });
//Re-enable clickable links
$("body").find("a").unbind("click");
My current ajax script is:
$(document).ready(function() {
$(".button").on("click",function() {
//Disable all other links
$.ajax({
type: "POST",
url: "launch.php",
data: {FID:$(this).attr('id'),Length:$('#FireLength').val()},
success: function(e) {
//Re-enable other links once ajax is complete
}
});
return false;
});
});
What would be even better is, if the buttons were to grey out whilst waiting for the response. I have a demo script at http://joshblease.co.uk/firework/
One way using a variable disabled
$(document).ready(function() {
var disabled = false;
$('a').css('opacity','0.4');
$(".button").on("click",function() {
//Disable all other links
disabled = true;
$.ajax({
type: "POST",
url: "launch.php",
data: {FID:$(this).attr('id'),Length:$('#FireLength').val()},
success: function(e) {
//Re-enable other links once ajax is complete
disabled = false;
$('a').css('opacity','1');
}
});
return false;
});
});
$('a').click(function(event){
if(disabled)
event.preventDefault();
});
Update
Changed link opacity for a disabled effect.
I would use actual buttons, not links, and disable them when one is clicked. Use a class on the button distinguish it from other buttons that might be on the page.
<input type="button" class="launch" ... >
...
$(document).ready(function() {
$("input[type=button].launch").on("click",function(event) {
// We will handle the button, prevent the standard button press action.
event.preventDefault();
//Disable all other links
$('input[type=button].launch').disable();
$.ajax({
type: "POST",
url: "launch.php",
data: {FID:$(this).attr('id'),Length:$('#FireLength').val()},
success: function(e) {
//Re-enable other links once ajax is complete
$('input[type=button].launch').enable();
}
});
return false;
});
});
Further manage it with a flag as #MonkeyZeus suggests.
I'd manage this with a class (assuming there might be some links you want to work). All the links that you want to not work give them the class blockable.
You can also then style your a.disabled class in your css to grey out the links (or whatever you want)
$(document).ready(function() {
$(a.blockable).click(function(e) {
if($(this).hasClass('disabled'))
{
e.preventDefault();
}
}
$(".button").on("click",function() {
$('a.blockable').addClass('disabled');
$.ajax({
type: "POST",
url: "launch.php",
data: {FID:$(this).attr('id'),Length:$('#FireLength').val()},
success: function(e) {
$('a').removeClass('disabled');
}
});
return false;
});
});
I would approach this by declaring a variable and only allowing AJAX to fire if variable has not been tripped:
$(document).ready(function() {
var launch_processing = false;
$(".button").on("click",function() {
if(launch_processing === false){
launch_processing = true;
$.ajax({
type: "POST",
url: "launch.php",
data: {FID:$(this).attr('id'),Length:$('#FireLength').val()},
success: function(data) {
},
complete: function(){
launch_processing = false;
}
});
}
else{
alert('Are you mad?!?! Fireworks are in progress!');
}
});
});

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 AJAX triggering too quickly

I have a relatively simple jQuery AJAX call wrapped in a function and I am testing my error functionality. The problem I am facing is the AJAX call happens too quickly! It is causing my 'H6' and '.loading' elements to start repeating. The behaviour I require is to remove the elements, then call the ajax.
function getAvailability(form) {
var str = $(form).serialize(),
warning = $('#content h6');
if ( warning.length > 0 ) {
$(warning).remove();
$('<div class="loading">Loading…</div>').insertAfter(form);
}
else
{
$('<div class="loading">Loading…</div>').insertAfter(form);
}
$.ajax({
type: "POST",
url: "someFile",
data: str,
success: function(calendar) {
$('.loading').fadeOut(function() {
$(this).remove();
$(calendar).insertAfter(form).hide().fadeIn();
});
},
error: function() {
$('.loading').fadeOut(function() {
$('<h6>Unfortunately there has been an error and we can not show you the availability at this time.</h6>').insertAfter(form);
});
}
});
return false;
}
I would love to sequence it like so -> Remove 'warning' from page, add .loading. Then trigger AJAX. Then fade out .loading, add & fade in warning/calendar dependent on success.
I have amended my original code, and I have got the function to behave as expected, primarily because I have disabled the submit button during the ajax process.
function getAvailability(form) {
var str = $(form).serialize(),
btn = $('#property_availability');
// Disable submit btn, remove original 'warning', add loading spinner
btn.attr("disabled", "true");
$('.warning').remove();
$('<div class="loading">Loading…</div>').insertAfter(form);
$.ajax({
type: "POST",
url: "public/ajax/returnAvailability1.php",
data: str,
success: function(calendar) {
$('.loading').fadeOut(function() {
$(this).remove();
$(calendar).insertAfter(form).hide().fadeIn();
});
},
error: function() {
$('.loading').fadeOut(function() {
$(this).remove();
$('<h6 class="warning">Unfortunately there has been an error and we can not show you the availability at this time.</h6>').insertAfter(form);
btn.removeAttr("disabled");
});
}
});
return false;
}
I believe that the original sequence was not working as expected due to the time delay created by the fadeOut() functions.
Instead of adding and removing warning, why not just show/hide leveraging ajaxStart and ajaxStop?
warning.ajaxStart(function() {
$(this).show();
}).ajaxStop(function() {
$(this).fadeOut();
});
If you need to sequence your events, then you should try using the deferred and promise methods that are a part of the jQuery.ajax API. This article does a good job of introducing them: http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html

Trouble with jquery ajax and datatables

I am trying to use jquery ajax to get data from a php file. This php file prints a table made from a db query. Once the table is returned to the html page, I wanted to apply datatables styling to the table, but this will not work.
It maybe that I should just use datatables ajax functionality, instead of jquery ajax. I just have three links that a user can click on to call ajax, where not all the links return a printed table.
I suspect it it because of javascript timing, where all the js loads before the table has been output.
I tried using jquery.on(), but could not get it to work with datatables.
I appreciate any help. Sorry if this is confusing.
<script type="text/javascript">
$(document).ready(function() {
// EVENT LISTENER FOR CLICKS
var option_action = "fridge";
var using = "pantry";
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
load_table();
});
// EVENT LISTENER FOR CLICKS
$(".pantry_menu li").click(function() {
alert("CLICK");
//getting data from the html
var option_action = $( this ).attr("name");
var using = "pantry";
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
});
return false;
});
//Mouse action listeners for side bar
$(".pantry_menu li").mouseover(function() {
$(this).css("border-bottom" , "2px solid black");
});
$(".pantry_menu li").mouseout(function() {
$(this).css("border-bottom" , "2px dotted black");
});
$(".fridge_table1").change(function(){
alert("CHANGE");
});
});
function load_table()
{
$('.fridge_table1').dataTable( {
"aaSorting": [[ 4, "desc" ]]
,"bJQueryUI": true
});
}
</script>
In your ajax success function, you can reapply dataTable to the table. For example:
$.ajax({
type: "POST",
url: "ajax.php",
data: {
request: 'something'
},
async: false,
success: function(output)
{
$('#myTableDiv').html(output); //the table is put on screen
$('#myTable').dataTable();
}
});
EDIT due to your update
You need to change the "EVENT LISTENER FOR CLICKS" to call your function that applies dataTables. Change:
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
});
to
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
load_table();
});
You should put the .dataTables() part in the callback of your ajax function
$.ajax{
url: yoururl,
...
success: function(data){
//append the table to the DOm
$('#result').html(data.table)
//call datatables on the new table
$('#newtable').dataTables()
}
otherwise you are trying to transforma table that doesn't exist yet in the DOM

Categories