Abort previous AJAX call when a new one made? - ajax

I'm updating search results as the user types the search term.
When 2 ajax calls happen, sometimes the last one data_response is brought back first. I need to make sure this doesn't happen.
This is my code:
function filterCities(search) {
$.ajax({type:'GET',url:'/ventas/theme/citiesContainer.php',data: "search=" + search,
success:function(data_response){
results.innerHTML = data_response;
}});
}
How do I cancell previous instances of the same request when I make a new one?

This is a solution with a simple counter:
<script>
var counter = 0;
function filterCities(search,c) {
$.ajax({type:'GET',url:'/results.php',data: "search=" + search,
success:function(data_response){
if(c == counter) { // Only update if it's data_response from last call
results.innerHTML = data_response;
}
}});
}
</script>
<input type="text" onkeyup="counter++; filterCities(this.value,counter);">

You could transmit a counter in the URL, and send the counter back, and just ignore the results if they aren't from the most current iteration. Much like a sequence number in UDP packets.

You need to look for an ajax queue plugin (or write one)
How do I go about getting the Ajax Queue plugin working in jQuery 1.3?
just search some more here on SO and google for "jquery ajax queue"

Related

Website loses performance after some jQuery $.ajax calls

I admit I'm quite noob with full ajax websites, and so I'm surely making some mistakes.
The problem is this:
in http://lamovida.arabianessence.com
every page is loaded with an $.ajax call using this function
function getAjaxPage() {
$('a.ajaxc').click(function() {
$("li.page_block").find(".wrapper").fadeOut(400).remove();
hideSplash();
var $thishref = $(this).attr('href'),
$thisurl = $thishref.replace("#!/",""),
$urlArr = $thisurl.split('-'),
$urlOk = $urlArr[0],
$dataOk = $urlArr[1];
$.ajax({
url : $urlOk + ".php",
data : 'id='+$dataOk,
success : function (data,stato) {
$("#content").css({opacity:1}).fadeIn(400);
$("li.page_block").html(data);
$("li.page_block").css('visibility', 'visible');
$("li.page_block").find(".wrapper").css({opacity:0}).show().animate({opacity:1},1000);
var $whgt = $(".wrapper").height(),
$ctop = ( ( $(window).height() - $whgt ) /2 )-40;
$("#content").stop().animate({height: $whgt+40, top: $ctop},1000);
$("li.page_block").css('padding-top',20);
$('.scrollable').jScrollPane();
$('.slider>ul>li').jScrollPane();
getAjaxPage();
},
error : function (richiesta,stato,errori) {
alert(errori);
}
});
});
}
Every time this function is called the content gets loader slower, and after about 20 clicks things get real bad, and the loading time grows and grows.
I tried to analyze the situation using the Google Chrome's Timeline, and I saw that after each click the browser uses more memory. If I comment the getAjaxPage(); row in the "success" section the situation starts to get better, but of course I lose all the internal navigation.
What could I do to avoid this problem?
Many thanks to all!
Every call to $('a.ajaxc').click() is adding new event handler thus every click causes more requests to be made. After the first click, every click will cause two requests. Another click? Another three requests. Etc.
Put the handler outside the function and you will have only one AJAX call per click:
$(document).ready(function() {
$('a.ajaxc').click(getAjaxPage);
});
I also don't see the reason behind calling getAjaxPage again from within the callback, so remove it as well to avoid infinite loop of requests.

Problems with HtmlUnit

I'm trying use HtmlUnit to submit a form, there are two select in my form, when i selected the first select, his call a function ajax and load the second select, follow my code:
HtmlPage page5 = anchor.click();
HtmlForm form = page.getFormByName("form1");
HtmlSelect state = form.getSelectByName("ddlMarca");
state.setSelectedAttribute(state.getOptionByValue("56"), true);
state.fireEvent(Event.TYPE_CHANGE);
HtmlSelect city = form.getSelectByName("ddlModelo");
for (HtmlOption option : city.getOptions()) {
System.out.println("city : "+option.asText()+" valor: " +option.getValueAttribute());
}
I'm using the method fireEvent to call event change, but does't work, How I can do this event work?
It may be working but you're not giving the browser time to make the ajax call, get a response and edit the dom. If the page makes an ajax call after firing the change event, try letting the page wait for a moment before checking again.
I haven't tested the below code so I can't say for certain this will solve you're issues, but I have used this technique to solve a similar issue.
You'll have to find something on the page that changes when the ajax call is completed for this to work. From the above question I'm assuming that changing one select populates the 2nd select box.
state.fireEvent(Event.TYPE_CHANGE);
//try 20 times to wait .5 second each for filling the page.
for (int i = 0; i < 20; i++) {
if (condition_to_happen_after_js_execution) {
break;
}
synchronized (page) {
page.wait(500);
}
}
HtmlSelect city = form.getSelectByName("ddlModelo");
for (HtmlOption option : city.getOptions()) {
System.out.println("city : "+option.asText()+" valor: " +option.getValueAttribute());
}
Example pulled from: http://htmlunit.sourceforge.net/faq.html#AJAXDoesNotWork

Using Form Validation submitHandler to send 2 AJAX requests?

I've got a pretty strong understanding of php, html & css but i've only just started to dive into javascript & jQuery.
The problem i'm facing is that I have a form on a page that I want first to validate, then when it passes validation to submit 2 ajax requests; the first to insert data into a table in my database and the second to run a query on another table and return the result.
I've got the latter working just fine using the submitHandler method to send the ajax request and update a div on my page with it's result. When I added a second ajax call after or before this one it seems to break...
My question is should there be a problem with having 2 ajax calls in the submitHandler, like below, and if so what would be the correct way to go about this, or even a better way?
$("#contactform").validate({
rules: ...
submitHandler: function() {
// First to insert the contact details using input#firstname etc.
var firstname = $("#firstname").value();
var lastname = $("#lastname").value();
var contactString = 'firstname='+ firstname + '&lastname=' + lastname;
$.ajax({
type: "POST",
url: "insertcontact.php",
data: quoteString,
success: function(server_response){
$('#yourquote').html(server_response).show();
}
});
// Second use width & height submitted from previous page for processquote.php
var width = <?php echo json_encode($cleanpost['width']); ?>;
var height = <?php echo json_encode($cleanpost['height']); ?>;
var quoteString = 'width='+ width + '&height=' + height;
$.ajax({
type: "POST",
url: "processquote.php",
data: quoteString,
success: function(server_response){
$('#yourquote').html(server_response).show();
}
});
}
});
I'm using the 'jquery.validate.js' validation plugin. Again my goal is such that once someone has entered valid details on my form, using Ajax their contact data is inserted into the database then the database is queried using fields submitted on the previous page to retrieve a numerical result to display on the page, without a refresh.
Any pointers you could give me would be much appreciated!
Rob
EDIT: Learning Javascript & Jquery simultaneously isn't such a good idea it seems, i've confused: this.value = ''; with $(this).val(''); as shown in the first 2 variable declarations, this is what was causing problems! Thanks for your useful help anyway guys, will upboat for your assistance.
In your first .ajax() call, you are trying to pass it a value in the data: parameter that you have not created yet. I believe you are wanting to send it the contactString instead.
Unless your two queries depend on each other being done sequentially then you should be able to execute them both asynchronously (essentially at the same moment). If you want the second AJAX call to happen after the first one, you could always pass all of your data parameters to insertcontact.php and once the insertion is done, execute processquote.php with the values you already passed through.
Lastly, I wonder if you are meaning to do this, but both of your AJAX calls overwrite whatever is in the #yourquote DOM element and show it. You might want to provide a separate element to put the response in for each of your two requests. Perhaps #yourquoteinserted and #yourquoteprocessed?
Edit: BigRob, from your comment it sounds as if you want to make synchronous AJAX queries, check out the async property of your .ajax() call. This is from the .ajax() documentation:
async Boolean
Default: true
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active.
(emphasis mine)
However, I could be wrong about this but you might actually be able to call one asynchronous AJAX method from within the success function of another. If it starts looking too intermingled for you, you might want to extract the inner call into a function. Rough approximation of what it might look like:
$.ajax({url, data:contactString,
success: function(server_response) {
extractedId = server_response; // you can return data many ways
$.ajax({url2, data:quoteString+"&extra="+extractedId,...
});
}
});
If you perform a synchronous call by setting async:false in the first AJAX call, then you could just store the result into an external (to the AJAX call) variable (or if that doesn't work store it in some DOM element temporarily). Then the javascript will pause execution and won't fire your second AJAX call until the first one has returned.
This is all hypothetical for now, though, and just based off of my understanding of how it should work.

simulating the "add another item" ajax call in drupal 7 using jquery

I am trying to get jQuery to send a mousedown event to the Drupal 7 "add another item" button for a multi-value field, then wait until the ajax call has completed before filling in that new blank row with data from an element in a jQuery object (that has several elements). I need to use a loop to cycle through the elements (ingredients) in this jQuery object, but no matter what I try my page dies...
Currently, I have something like the following:
i = 0;
ingredients = newHtml.find('.recipe_ingredients > li');
ingredientsLength = ingredients.length;
$('#edit-field-ingredients-und-add-more').mousedown();
while(i < ingredientsLength) {
if ( document.readyState !== 'complete' ) {
// code to fill in the new blank row with data from 'ingredients'
$('#edit-field-ingredients-und-add-more').mousedown();
i++;
}
}
Because I don't yet know how to issue the ajax call myself using jQuery (or using Drupal) I've been trying to just check whether the call has completed by using .readyState and other hack-like methods. I'm just not sure what to try next!
Am I going about this the completely wrong way? Is there a straightforward way to make the "add another item" multi-value field ajax call using jQuery? Any help would be greatly appreciated...
I am not sure if there's a nicer way in Drupal 7, but in Drupal 6 you could use jQuery(document).ajaxComplete with the settings.url property to tell when a specific "Add another item" click had finished.
Start with:
(function($) {
$(document).ajaxComplete(function(e, xhr, settings)
{
alert(settings.url);
});
}(jQuery));
Once you've identified the right settings.url for your field, change that to:
(function($) {
$(document).ajaxComplete(function(e, xhr, settings)
{
if (settings.url == "the path from step 1") {
// Code to populate your fields here
}
});
}(jQuery));
And voila!
You might want to read the page by Jay Matwichuk where I originally learned this technique awhile back. All credit to him (and nclavaud for his comment there), really.

Assign jQuery.get() to a variable?

What is the correct way of assigning to a variable the response from jQuery.get() ?
var data = jQuery.get("output.csv");
I was reading that jQuery.get() must have a callback function? why is that? and how would i use this callback function to assign the response back to the data variable?
Thanks in advance for your help and clarification.
Update:
Thank you all for your answers and explanations. I think i am starting to finally grasp what you are all saying.
My code below is doing the right thing only the first iteration of it.
The rest of the iterations its writing to the page undefined.
Am i missing something?
<tbody>
<table id="myTable">
<script type="text/javascript">
$.get('output.csv', function(data) {
csvFile = jQuery.csv()(data);
for ( var x = 0; x < csvFile.length; x++ ) {
str = "<tr>";
for ( var y = 0; y < csvFile.length; y++) {
str += "<td>" + csvFile[y][y] + "</td>";
}
str += "</tr>";
}
$('#myTable').append(str);
});
</script>
</tbody>
</table>
A callback function is required for asynchronous function calls, like an AJAX GET request. There is a delay between calling the get function and getting a response back, which could be a millisecond or several minutes, so you need to have a callback function that gets called when the asynchronous GET has completed its work.
Here's some more info on jQuery's AJAX get function: http://docs.jquery.com/Ajax/jQuery.get#urldatacallbacktype.
From jQuery's examples:
// this would call the get function and just
// move on, doing nothing with the results
$.get("test.php");
// this would return the results of the get
$.get("test.php", function(data){
alert("Data Loaded: " + data);
});
If you get undefined when you try to use the data variable in the callback function, open up the console in Firebug in Firefox and watch the get request. You can see the raw request and the response that it comes back with. You should get a better indication of the issue after seeing what's being sent to the server and what's being sent back to the client.
tsvanharen answered the question well, but DCrawmer's still missing the point. Let me attempt a clarification for him. I'm oversimplifying some of this, and smoothing over some details.
Look at the code shown below. This is pretty much the same code as tsvanharen's, except that I've replaced the anonymous function for the callback with an actual function pointer, and am a little more explicit so you can see what's going on:
var x = null;
function myCallback(data)
{
alert("Data Loaded:" + data);
}
$.get("test.php", myCallback);
// the rest of your code
alert("The value of X is: " + x);
Assuming that test.php takes even a moment or two to load, notice the order that the alerts probably come up in:
1. "The value of X is"
2. "Data Loaded"
The function $.get() runs instantaneously. JavaScript moves on and runs the rest of your code right away. In the background, it's retrieving your page at test.php. jQuery hides some of the messy details of this.
The callback function (the second argument to $.get()) runs later (asynchronously). Or, said another way, the function myCallback is a handler to an event. That event is "$.get() has finished retrieving the data". It doesn't get run until that point. It doesn't run when $.get() runs! $.get() just remembers where that function is for later.
The function myCallback may run milliseconds or minutes later, long after $.get() has been dealt with.
If myCallback doesn't run until minutes later, then what's the value of x when the "The value of X" code is run? It's still null. There's your bug.
To use the data retrieved from the page in your script, you have to do things more like this:
Start your script, declare your variable to hold the data.
Call $.get(), with a callback function to handle the return.
Do nothing else. [Or, at least, nothing that requires the data]
Let the page just sit there.
...sometime in the future...
X. Your callback function will get run, and have the results of your web page.
Your callback function can:
* Display the data
* Assign that data to a variable
* Call other functions
* Go along it's merry way.
Actually in your example the data will be the XMLHttpRequest request object.
var x;
$.get( 'output.csv', function(data){
x = data;
console.log(x); // will give you the contents.
});
I really struggled with getting the results of jQuery ajax into my variables at the "document.ready" stage of events.
jQuery's ajax would load into my variables when a user triggered an "onchange" event of a select box after the page had already loaded, but the data would not feed the variables when the page first loaded.
I tried many, many, many different methods, but in the end, the answer I needed was at this stackoverflow page: JQuery - Storing ajax response into global variable
Thanks to contributor Charles Guilbert, I am able to get data into my variables, even when my page first loads.
Here's an example of the working script:
jQuery.extend
(
{
getValues: function(url)
{
var result = null;
$.ajax(
{
url: url,
type: 'get',
dataType: 'html',
async: false,
cache: false,
success: function(data)
{
result = data;
}
});
return result;
}
}
);
// Option List 1, when "Cats" is selected elsewhere
optList1_Cats += $.getValues("/MyData.aspx?iListNum=1&sVal=cats");
// Option List 1, when "Dogs" is selected elsewhere
optList1_Dogs += $.getValues("/MyData.aspx?iListNum=1&sVal=dogs");
// Option List 2, when "Cats" is selected elsewhere
optList2_Cats += $.getValues("/MyData.aspx?iListNum=2&sVal=cats");
// Option List 2, when "Dogs" is selected elsewhere
optList2_Dogs += $.getValues("/MyData.aspx?iListNum=2&sVal=dogs");
You just need to specify the callback function in the parameter to get method. Your data will be in the variable you specify in the function.
$.get("output.csv", function(data) {
// Put your function code here, the 'data' variable will hold your data.
});

Resources