JQuery prevent links working whilst ajax is loading - javascript

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!');
}
});
});

Related

AJAX async:true breaks site on mobile browsers

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);

How can I bind a onclick event to a checkbox INSTEAD of a change event?

Here is the problem I have.
I'm making a control panel for some devices. Now the user can enable/toggle an on/off switch (checkbox) and so can a remote device. This is reflected in the database.
However, I also want a confirm box whenever the user (NOT the device) toggles to enable the device (checkbox == checked). No confirmation box required for when the user disables (toggles off, checkbox==false) the device.
I check the database every few seconds to see the state of device (since the device can turn itself on or off)
This is what I have so far (It doesn't work correctly. Nothing is sent to the database. on click doeesn't fire on user click in checkbox)
$(function() {
$('#toggle').bootstrapToggle({
on: TR_Toggle_On,
off: TR_Toggle_Off
});
check_enable();
function check_enable() {
var timer = setInterval(function(result) {
$.ajax({
type: "get",
url: "checkState.php",
success: function(result) {
var enabled =parseInt(result);
if (enabled ===1) {
$( '#toggle').bootstrapToggle('on');
} else {
$( '#toggle').bootstrapToggle('off');
}
}
});
}, 5000);
}
$('#toggle').on('click',function(){
$('#toggle').change(function() {
if ($('#toggle').prop('checked') ===true) {
if(confirm("Sure?")){
$.ajax({
type: "get",
url: "setEnable.php",
data: "enable=1"
});
}else{
$('#toggle').prop('checked',false);
}
} else {
$.ajax({
type: "get",
url: "setEnable.php",
data: "enable=0"
});
}
})
})
})
How can I do this? When I try to register the on('click',func(){}) event, nothing fires. I assume it doesn't work for checkboxes? What am I doing wrong?
You're binding an event within another event..
$('#toggle').on('click',function(){
$('#toggle').change(function() {
...
}
}
You should only bind once, like this...
$('#toggle').on('click',function(){
if ($('#toggle').prop('checked') ===true) {
if(confirm("Sure?")){
$.ajax({
type: "get",
url: "setEnable.php",
data: "enable=1"
});
}else{
$('#toggle').prop('checked',false);
}
} else {
$.ajax({
type: "get",
url: "setEnable.php",
data: "enable=0"
});
}
}
Yes it works for checkboxes.
Tried a minimal example like this:
<input type="checkbox" class="toggle" name="dog" value="TinyDog" /> what does the dog say
$(document).ready(function() {
$('.toggle').on('click',function(){
alert("woff woff");
});
});
Try adding some console.log lines or alerts to see where your code fails.

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 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

jQuery.ajax not working in IE7/8

Something in my script is breaking IE.
I'm looking on a collection of links with a class, and hijacking the URL's.
Clicking a link will animate the height and reveal a message. It also
does an ajax request to mark the message as read.
However, in IE it simply goes to the URL instead of staying on the page and processing the http request.
$('.message .subject .subject_link').click(function(e) {
toggle_message(e)
return false;
});
function toggle_message(m) {
var link = m.target;
var parent = $(link).parent().parent();
console.log(link.href);
$.ajaxSetup({
url: link.href,
dataType: 'json',
timeout: 63000,
type: 'GET',
cache: false
});
if($(parent).hasClass('unread')) {
$(parent).addClass('read').removeClass('unread');
$.ajax({
complete: function(r, textStatus) {
console.log(r.responseText)
}
});
}
if($(parent).find('.body_wrapper').hasClass('collapsed')) {
$(parent).find('.body_wrapper').addClass('expanded').removeClass('collapsed');
$(parent).find('.body_wrapper').animate({
height: 'toggle'
})
} else {
$(parent).find('.body_wrapper').addClass('collapsed').removeClass('expanded');
$(parent).find('.body_wrapper').animate({
height: 'toggle'
})
}
}
any ideas what's causing this issue?
http://support.cooper.krd-design.net/
tester: 12345 if you want to review the page
Thanks
Rich
Adding
e.preventDefault();
before toggle_message in the first function should work, although return false should as well.
I don't have access to IE right now but I think you could try preventing the default click event to fire in your click()-function like so:
$('.message .subject .subject_link').click(function(e) {
toggle_message(e)
e.preventDefault();
});
More on .preventDefault() here: http://api.jquery.com/event.preventDefault/

Categories