jQuery AJAX triggering too quickly - javascript

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

Related

Can't get rid of a flash of content from after ajax page load

I have a page that makes different ajax calls based on what element one clicks on. There are four IDs and only one should be visible at any given moment. My problem comes when I load new ajax content into a div - I get a flash for a very brief second of the previous content. Here is one of my functions for one of the calls (they are all essentially the same). At the beginning of the function I hide everything. Then after the ajax has loaded I show the relevant div. I'm confused about why this would not work. There should be no flash, since all the div are hidden, right?
$('body').on("click", "#answer-submit", function() {
$('#games, #location, #question, #answer').css('display' , 'none');
var theAnswer = $('#challenge-answer').val();
$.ajax({
type: "POST",
url: "ajax/answer.php",
data: { answer : theAnswer },
dataType: "html",
success: function(msg){
if(parseInt(msg)!=0) {
$('#answer').html(msg);
}
}
});
$('#answer').css('display' , 'block');
});
The problem is an asynchronous request is going to happen asynchronously. In other words, your success function is going to be called after $('#answer').css('display' , 'block'); (it is a race condition but it's practically guaranteed). The solution is simple -- move $('#answer').css('display' , 'block'); into the success function:
$('body').on("click", "#answer-submit", function() {
$('#games, #location, #question, #answer').css('display' , 'none');
var theAnswer = $('#challenge-answer').val();
$.ajax({
type: "POST",
url: "ajax/answer.php",
data: { answer : theAnswer },
dataType: "html",
success: function(msg){
if(parseInt(msg)!=0) {
$('#answer').html(msg);
$('#answer').css('display' , 'block');
}
}
});
});
You can even chain it like so:
if (parseInt(msg) != 0) {
$('#answer')
.html(msg)
.css('display', 'block');
}

jQuery onclick event not working upon making multiple ajax requests

I am making few ajax requests in my jQuery file. On success of these jQuery requests, I wrote few on click events which are not working.
This is my code
$(document).ready(function (){
$.ajax ({
type: "POST",
url: 'myServlet',
async: false,
success: function (response) {
id = parseInt(response);
setOutputEvents();
}
});
function setOutputEvents() {
for (var queryNumber = 0; queryNumber <= id; queryNumber++) {
$.ajax({
type: "POST",
url: 'myOtherServlet',
data: {queryNumber: queryNumber},
success: success,
async: false
});
var success = function (response) {
//some code here
generateTable();
}
}
}
function generateTable () {
//some code here
pagination();
}
function pagination(){
$(".class").click(function(event) {
alert();
});
}
$("#me").on("click", function(){
alert("me is triggered");
});
});
I understand making multiple ajax requests is a bad programming practice but what could be the reason for on click events not getting triggered?
These are the onclick events which are not working.
function pagination(){
$(".class").click(function(event) {
alert();
});
}
$("#me").on("click", function(){
alert("me is triggered");
});
I am using Google Chrome Version 39.0.2171.95 on Windows 7.
Please do let me know if any further information is necessary.
Since you use ajax to load even the initial content it seems, .class / #me html elements likely do not exist on initial page load of the DOM. As you didn't post html, i'm guessing this is the case.
Thus, you need to use a delegated event click handler to respond to it
so, you would change
$("#me").on("click", function(){
to
$(document).on("click", "#me", function(){
and so forth to link it to the parent element that does exist, the document itself.
This would work:
$(".class").on("click", function(){
alert("me is triggered");
});
function generateTable () {
//some code here
pagination();
}
function pagination(){
$(".class").trigger("click");
}
Some notes:
Event handler must be registered before triggering click.
Triggered click selector must match the class which has the click event registered.
Functions must be defined before the usage.

Call jquery function when one function completes

So I have a jquery click function assigned to an on/off toggle. Very simple script:
$('.on-off').on('click', function(e) {
e.preventDefault();
var $this = $(this);
$this.find('.slider').toggleClass('active');
});
We have two versions of this toggle. One toggles instantly when clicked and then we submit the value when clicking next(aka submit).
Our other one calls a jquery ajax function that toggles on success and upon success if it is a specific message code that is defined on the backend.
jQuery.ajax({
url: url,
type: 'POST',
dataType: 'json',
cache: false,
data: {'requestType': requestType},
success: function(message) {
if(message.STATUS=='2000'){
if(currentButtonClicked=='dashboardChargingButton'){
if($('#dashboardChargingButton').html()==startCharge)
$('#dashboardChargingButton').html(stopCharge);
else
$('#dashboardChargingButton').html(startCharge);
}
if(currentButtonClicked=='invokeChargingButton'){
$( "#invokeChargingButton .slider" ).toggleClass( 'active');
}
}
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status + " - " + xhr.statusText);
}
});
}
As you can see I have to toggle the class again using the same code but with direct targeting.
The on off toggles of this type have an onclick inside the actual html calling the function that handles this ajax.
My goal is to have my first set of code the one that targets the element and toggles the class to do all of this, but dynamically to where we don't have to call a function everytime.
Conceptually what I thought is:
$('.on-off').on('click', function(e) {
e.preventDefault();
var $this = $(this);
if (!$this.attr('onclick')) {
$this.find('.slider').toggleClass('active');
} else {
var clickFunction = $this.attr('onclick');
call the clickFunction
if (clickfunction = true) {
$this.find('.slider').toggleClass('active');
}
}
});
What this would do is grab the onclick, but not call it until I specify. And inside the ajax request instead of toggling I would just return true.
This might not be the best method. I am just trying to ecapsulate everything to limit the amount of code as well as make all the dom changes for those elements in one spot for any potential defects.
Here is a link to a basic fiddle of the on/off toggle.
Fiddle
I hope I explained everything in good enough detail.

Reinitialize jQuerytools Overlay on ajax loaded element

I am trying to reinitialize a Overlay on new ajax loaded elements.
Here my code:
$('input.search-files').keyup(function(event){
if( event.keyCode == 13 ) {
$.ajax({
type: "GET",
url: ...,
dataType: "html",
data: {...},
beforeSend: function(){
$('.tr-documento').fadeOut('fast', function(){ $(this).remove(); });
$('.table-content').find('.table-loader').show();
},
success: function(data) {
if( $(data).filter('tr').length == 0 ){
$('.table-loader').before( '<tr class="tr-documento"><td colspan="10">Non ci sono</td></tr>' );
} else{
$('.table-loader').before( $(data).filter('tr') );
}
$('.table-content').find('.table-loader').hide();
$("table.table-content").tablesorter({headers: { 0: { sorter: false }, 6: { sorter: false },7: { sorter: false },8: { sorter: false },9: { sorter: false } } });
reInitializeAjaxed();
$(".modifica-file[rel]").overlay();
}
});
}
});
This function is triggered on "ENTER" keyup.
Everything work fine, table sorter works at first hit.
jQuerytools overlay event instead, is binded only at the second hit on "ENTER".
Someone knows this issue?
Is there a way to "live" overlay event and not re-init each ajax call?
I tried this:
$(document).delegate('.modifica-file[rel]', 'load', function(){ $(".modifica-file[rel]").overlay(); });
but is not working..
I think is not opened because the overlay is only initialized without firing.
You can set the load attribute at true like:
$(".modifica-file[rel]").overlay({load: true});
or fire the overlay manually using the load method:
$(".modifica-file[rel]").data("overlay").load();
Docs: http://jquerytools.org/documentation/overlay/
Example: http://jquerytools.org/demos/overlay/trigger.html
I found solution here: http://flash.flowplayer.org/forum/tools/40/21252
There are many solutions on this link, i am using the following:
$(".modifica-file[rel]").live('click', function () {
$(this).overlay().load();
$(this).overlay().load();
return false;
});
I think this is quite dirty solution...$.live() method is not supported anymore on latest jQuery versions...but i am using 1.7.2 and it is working fine!
I added this snippet to end of SUCCESS AJAX callback.

jQuery plugin bsmSelect doesn't update its values when it is called again and its select options have changed

I'm using bsmSelect jQuery plugin. Basically, what it does is changing the way a select-multiple is rendered to make easier to pick up the options. It hides the select element and shows a list instead.
So, first of all I'm applying the plugin function to my select-multiple element:
$(document).ready(function() {
...
$('#my_select_multiple').bsmSelect({
plugins: [$.bsmSelect.plugins.sortable()],
title: 'Add',
removeLabel: 'Remove'
});
...
});
On the other way, I have another select element (this one is simple) which has an ajax request bind to its change event. This ajax request get new #my_select_multiple options depending on the select simple value. Ajax response is the new HTML for #my_select_multiple options. So I have:
function getNewOptions(val) {
var r = $.ajax({
type: 'GET',
url: /*My URL*/
}).responseText;
return r;
}
...
$(document).ready(function() {
...
$('#my_select_simple').change() {
$('#my_select_multiple').html(getNewOptions($(this).val()));
}
...
});
AJAX is working as expected. New options are got correctly and they are inserted into #my_select_multiple (which is hidden by bsmSelect plugin, but I can check it with Firebug). But bsmSelect didn't realize new changes and doesn't get updated.
So, I think what I want is to reapply $('#my_select_multiple').bsmSelect(); with its new options.
I've been looking around a little bit and here is what I have tried.
1. I've tried to call again the funcion with the success and complete (one at time) of the AJAX request. Didn't work:
function getNewOptions(val) {
var r = $.ajax({
type: 'GET',
url: /*My URL*/,
success: function() { $('#my_select_multiple').bsmSelect(); }
}).responseText;
return r;
}
2. I've tried to bind the function with the on jQuery function. Didn't work:
$('#my_select_simple').on('change', function() {
$('#my_select_multiple').bsmSelect();
});
3. I've tried 1 and 2 removing previosly the HTML generated by bsmSelect. Didn't work.
Thank you very much.
UPDATE: The exact code
First I have a global.js file which apply bsmSelect plugin to some select multiples (.quizzes):
$('.quizzes').bsmSelect({
plugins: [$.bsmSelect.plugins.sortable()],
title: 'Add',
removeLabel: 'Remove'
});
And then, in the php file I define the updateQuizzes function and bind it to the select simple (project_id) change event:
<script type="text/javascript">
function updateQuizzes(project_id) {
var r = $.ajax({
type: 'GET',
url: '<?php echo url_for('event/updateQuizzes')?>'+'<?php echo ($form->getObject()->isNew()?'':'?id='.$form->getObject()->getId()).($form->getObject()->isNew()?'?project_id=':'&project_id=')?>'+project_id,
success: function() { $('.quizzes').bsmSelect({
plugins: [$.bsmSelect.plugins.sortable()],
title: 'Add',
removeLabel: 'Remove'
}); }
}).responseText;
return r;
}
$('#project_id').change(function(){
$('.quizzes').html(updateQuizzes($(this).val()));
});
</script>
As I told, the AJAX request works without problems, but not the calling bsmSelect the second time...
Not sure if this is what the problem is, but you could try
$('#my_select_simple').change() {
$('#my_select_multiple').html(getNewOptions($(this).val())).trigger('change');
}
This triggers a change event on select_multiple, and might fire bsmSelect. I'm not sure what the problem here is exactly, but that's the best I can come up with.
I think you want to set your HTML in the success of the Ajax call, something like:
function loadNewOptions(val) {
$.ajax({
type: 'GET',
url: /*My URL*/,
success: function(data) {
$('#my_select_multiple').html(data).bsmSelect();
}
});
}
And then calling like:
$('#my_select_simple').change() {
loadNewOptions($(this).val());
}
$(document).ready(function() {
$('#my_select_simple').change() {
$('#my_select_multiple').load("your Url", function(){
$('#my_select_multiple').bsmSelect();
});
}
});
something like this should work.
.load will put whatever your url returns into #my_select_multiple
the first parameter is the url to load, and the 2nd is a function to call when it is done. which is where you need to set up your fancy selector.
Ok, I opened a ticket and bsmSelect developer has answered me in minutes. Great!
To let bsmSelect know about its select changes, you have to trigger a change event on the select. There is no need to call bsmSelect again.
So it can be that way:
function loadNewOptions(val) {
var r = $.ajax({
type: 'GET',
url: /*My URL*/,
success: function(data) {
$('#my_select_multiple').html(data).trigger('change');
}
}).responseText;
return r;
}
$('#my_select_simple').change(function() {
loadNewOptions($(this).val());
});

Categories