JavaScript ajax behavior - javascript

This is my first question, any suggestions on further questions will be appreciated.
When using the following code to update a table I don't see any updates, however when moving the TableList = {} into the success function, the table will update like intended.
Can someone give me an explanation to why I need to move the emptying of the object into the success block?
Answers I've read don't seem to help me understand any better.
function GetTableData() {
TableList = {};
$.ajax({
url: "http://localhost:3000/info/",
success: function (result) {
//Moiving 'TableList = {}' here works fine
for (var i = 0; i < result.length; i++) {
TableList[i] = result[i];
}
}
});
}
function UpdateTable() {
GetTableData()
//Update table cells
setTimeout(function () {
UpdateTable();
}, 1000);
}

$.ajax is asynchronous, so the response comes "later"
You call GetTableData() ...
first thing it does is clear TableList
second thing it does is begin the asynchronous call
then it returns
Your code then updates using the EMPTY TableList (becuase it hasn't been filled yet)
some time later, TableList is filled
a second later, repeat the fruitless loop
One solution is this
function GetTableData(callback) {
$.ajax({
url: "http://localhost:3000/info/",
success: callback
});
}
function UpdateTable() {
GetTableData(function(TableList) {
//Update table cells
setTimeout(UpdateTable, 1000);
});
}
Now the following happens
call GetTableData()
ajax starts
when data is received, the success function calls the callback with the response as the first argument
your callback code updates the table cells
then initiates a timeOut to repeat the whole thing again

Related

Nested Ajax Call not getting executed [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I am making nested Ajax call, here is code for that:
function getCheckListId() {
var authToken = getCookie("aqs_authToken");
//Lets say AjaxCall1
$.ajax({
....
// Basic Ajax definition (type, url, etc.....)
....
success: function (result) {
for (var i=0; i< result.length;i++) // ForLoop AjaxCall1
{
var sample= result[i].checklistDetailId;
// Lets say AjaxCall2
$.ajax({
url: 'URL' +sample
// Code for Another Ajax Call
success: function(result) {
for(var i=0; i<result1.length; i++) { { ... Some code.. }
} // END ForLoop AjaxCall2
toSendEmail();
// This is function call in which I am posting data (AjaxCall3)
}, // Success Function close for AjaxCall2
error: function(error) {.. some code.. }
} // Error function close for AjaxCall2
}
}); // Close of AjaxCall2
}, // Success Function close for AjaxCall1
error: function (error) {
alert("Some Statement");
} // Error Function Close for AjaxCall1
});
}
I am making AjaxCall2 in AjaxCall1' Success function. But my AjaxCall2 is not getting executed it is directly making the call to function toSendEmail()
I had look around and I tried like making function inside function (nested function) to make my ajax call executed but still not working.
Can anyone suggest me any another way to execute it? or What I need to change to get my AjaxCall2 executed BEFORE controller calls toSendEmail() method?
Thank You
toSendEmail() needs to go inside:
success: function(result) { ... Some code.. },.
Otherwise it will run before your second ajax call has returned. You are correctly calling the second ajax call in the success handler of the first, now you just need to put your final step inside the success handler of the second ajax call.

Stopping Code until AJAX call completes inside $.each loop

I have a function that loads HTML from an external file via an AJAX call using jQuery.
These ajax call runs inside of a $.each loop and I need this ajax call to finish before the loop continues. Here is my code:
$('img').each(function(){
var cotainer_html = $('.cotainer_html').clone();
/* Get Image Content */
$.ajax({
url: '/assets/ajax/get_studio_image.php',
type:'GET',
success:function(data){
cotainer_html.find('.replaceme').replaceWith(data);
}
});
});
I know I can set async:false but I hear that is not a good idea. Any ideas?
To achieve this you can put each request in to an array and apply() that array to $.when. Try this:
var requests = [];
$('img').each(function(){
var cotainer_html = $('.cotainer_html').clone();
/* Get Image Content */
requests.push($.ajax({
url: '/assets/ajax/get_studio_image.php',
type:'GET',
success:function(data){
cotainer_html.find('.replaceme').replaceWith(data);
}
}));
});
$.when.apply($, requests).done(function() {
console.log('all requests complete');
});
Note that you're replacing the same content on each request, so the only one which will have any effect on the UI is the last request. The preceding ones are redundant.
Also note that you should never, ever use async: false. It locks the UI thread of the browser until the request completes, which makes it look like it has crashed to the user. It is terrible practice. Use callbacks.
The OP appears to want the calls to run in series, not in parallel
If this is the case you could use recursion:
function makeRequest($els, index) {
var cotainer_html = $('.cotainer_html').clone();
$.ajax({
url: '/assets/ajax/get_studio_image.php',
type:'GET',
success:function(data){
cotainer_html.find('.replaceme').replaceWith(data);
if ($els.eq(index + 1).length) {
makeRequest($els, ++index);
} else {
console.log('all requests complete');
}
}
});
}
makeRequest($('img'), 0);
You can use a pseudo-recursive loop:
var imgs = $('img').get();
var done = (function loop() {
var img = imgs.shift();
if (img) {
var cotainer_html = $('.cotainer_html').clone();
/* Get Image Content */
return $.get('/assets/ajax/get_studio_image.php')
.then(function(data) {
cotainer_html.find('.replaceme').replaceWith(data);
}).then(loop);
} else {
return $.Deferred().resolve(); // resolved when the loop terminates
}
})();
This will take each element of the list, get the required image, and .then() start over until there's nothing left.
The immediately invoked function expression itself returns a Promise, so you can chain a .then() call to that that'll be invoked once the loop has completed:
done.then(function() {
// continue your execution here
...
});

Callback to prevent looping before completion of ajax

I have read countless examples of similar posts calling for help and also explanations of the theory behind callbacks, but I just can't grasp it. I have gotten to the stage where I'd rather find a solution for my particular scenario and move on even if I don't really understand 'why/how' it works.
I have an ajax call that needs to loop through and need to find a way to prevent the next call before the previous has completed. Could you suggest how I might use a callback or other method to make this happen.
Here's the code (which works, but doesn't run the ajax calls 1-by-1 so I'm getting memory errors and page crashes). The function that runs is quite intensive and can take up to 20 seconds (but as little as 1 second)
function returnAjax(startLoc,startRow)
{
var url='index.php?option=com_productfinderrtw&format=raw&task=goThroughProcess';
var data = 'startloc='+startLoc+'&starttour='+startRow;
var request = new Request({
url: url,
method:'get',
data: data,
onSuccess: function(responseText){
document.getElementById('fields-container').innerHTML= responseText;
//I realise this is where on-success code cneeds to go- is this where the callback belongs?
}
}).send();
}
function iterator (startLoc,startRow) {
if (startRow <20)
{
startRow++;
}
else
{
startRow = 1;
startLoc++;
}
return [startLoc, startRow];
}
function runRAA() {
var startLoc = 0;
var startRow = 1;
while (startLoc < 47)
{
returnAjax(startLoc,startRow);
$counter = iterator(startLoc,startRow);
var newLoc = $counter[0];
var newRow = $counter[1];
startLoc = newLoc;
startRow = newRow;
}
}
runRAA() is the main function that runs on a button press. How can I rearrange this to make sure that returnAjax doesn't run until the previous time is completed?
Thanks in advance for this. I KNOW that similar questions have been asked, so I beg that you don't direct me to other explanations- chances are I've read them but just don't grasp the concept.
Cheers!
PS. I understand that the iterator() function needs to run only when the returnAjax() is complete also, as iterator() sets the new parameter values for each instance of the returnAjax() function
Allow to pass a callback parameter that will be called when the ajax call is completed.
function returnAjax(startLoc, startRow, callback) {
//...
onSuccess: function(responseText) {
document.getElementById('fields-container').innerHTML= responseText;
if (callback) {
callback.apply(this, arguments); //call the callback
}
}
//...
}
Then you can do something like this:
function runRAA(startLoc, startRow) {
startLoc = startLoc || 0;
startRow = startRow || 1;
if (startLoc < 47) {
returnAjax(startLoc, startRow, function (responseText) {
var counter = iterator(startLoc, startRow);
//do something with the response
//perform the next ajax request
runRAA(counter[0], counter[1]);
}));
}
}
runRAA(); //start the process

in jQuery is there a ways to loop over an array such that before it loops to the next loop it first waits for the responce from the server?

Let me explain my situation,
I have a list of checkboxes in a fieldset, for each checkbox i would like to send a jquery get and wait for the response from the server which can be random time 10 seconds to a long time once i get the result display the result and continue to the next loop.
$(function() {
$("button[name=distributeGroupProgramsToCustomersNow]").click(function() {
event.preventDefault();
$("button[name=distributeGroupProgramsToCustomersNow]").attr("disabled", "");
$("input[name='distributeGroups-GroupsList']:checked").each(function ()
{
// the loop that waits for the response
});
$("button[name=distributeGroupProgramsToCustomersNow]").removeAttr("disabled", "");
});
});
How do i achieve this in jQuery?
Any help is greatly appriciated, Thanks!
You can do this by making the call to your ajax synchronous, that way the loop has to wait for the response before it can continue.
$.each(arrayOfItems, function(i,v){
$.ajax({
url: 'path/to/my/file.extension',
type: 'GET', //this is already the default, only placed as an example.
async: false, // this is what you want to make sure things 'wait'.
data: 'checkedValue='+v, //value of our item.
success: function(data){
//manipulate / insert the data where you need.
$("#someElement").append(data);
}
});
});
How it works
For each item, we have an ajax call. Disabling 'asynchronous' ajax forces the server to 'wait' on the previous AJAX request to be completed before processing the next AJAX request. This replicates the behavior that you want.
you can write a function that calls itself
var ajaxLoopInput = $("input[name='distributeGroups-GroupsList']:checked");
var i = 0;
ajaxIt(i);
function ajaxIt(index){
if(i < ajaxLoopInput.length){
ajaxLoopInput.eq(index).dosomething(); //if you need the current item in list.
$.ajax({
//your ajax stuff
success : function(){
i++;
ajaxIt(i);
}
});
}else{
return false;
}
}
The best way to handle this without blocking and using synchronous calls, is to use the array as a queue, and have a function that pulls the first item from the queue, runs the query, and then calls itself.
var myQueueArray = [1, 2, 3];
var currentIndex = 0;
function queueGet() {
if(currentIndex >= myQueueArray.length) {
return;
}
$.get("/my/url/", { 'checkedValue', myQueueArray[currentIndex] }, function(data) {
//this is the important part...call the queue again until it's done
currentIndex += 1;
queueGet();
});
}
The version above is non-destructive of the array. You could of course just pop the array too.

jQuery Ajax / .each callback, next 'each' firing before ajax completed

Hi the below Javascript is called when I submit a form. It first splits a bunch of url's from a text area, it then:
1) Adds lines to a table for each url, and in the last column (the 'status' column) it says "Not Started".
2) Again it loops through each url, first off it makes an ajax call to check on the status (status.php) which will return a percentage from 0 - 100.
3) In the same loop it kicks off the actual process via ajax (process.php), when the process has completed (bearing in the mind the continuous status updates), it will then say "Completed" in the status column and exit the auto_refresh.
4) It should then go to the next 'each' and do the same for the next url.
function formSubmit(){
var lines = $('#urls').val().split('\n');
$.each(lines, function(key, value) {
$('#dlTable tr:last').after('<tr><td>'+value+'</td><td>Not Started</td></tr>');
});
$.each(lines, function(key, value) {
var auto_refresh = setInterval( function () {
$.ajax({
url: 'status.php',
success: function(data) {
$('#dlTable').find("tr").eq(key+1).children().last().replaceWith("<td>"+data+"</td>");
}
});
}, 1000);
$.ajax({
url: 'process.php?id='+value,
success: function(msg) {
clearInterval(auto_refresh);
$('#dlTable').find("tr").eq(key+1).children().last().replaceWith("<td>completed rip</td>");
}
});
});
}
What you want is to run several asynchronous actions in sequence, right? I'd build an array of the functions to execute and run it through a sequence helper.
https://github.com/michiel/asynchelper-js/blob/master/lib/sequencer.js
var actions = [];
$.each(lines, function(key, value) {
actions.push(function(callback) {
$.ajax({
url: 'process.php?id='+val,
success: function(msg) {
clearInterval(auto_refresh);
//
// Perform your DOM operations here and be sure to call the
// callback!
//
callback();
}
});
});
}
);
As you can see, we build an array of scoped functions that take an arbitrary callback as an argument. A sequencer will run them in order for you.
Use the sequence helper from the github link and run,
var sequencer = new Sequencer(actions);
sequencer.start();
It is, btw, possible to define sequencer functions in a few lines of code. For example,
function sequencer(arr) {
(function() {
((arr.length != 0) && (arr.shift()(arguments.callee)));
})();
}
AJAX is asynchronous.
That's exactly what's supposed to happen.
Instead of using each, you should send the next AJAX request in the completion handler of the previous one.
You can also set AJAX to run synchronously using the "async" property. Add the following:
$.ajax({ "async": false, ... other options ... });
AJAX API reference here. Note that this will lock the browser until the request completes.
I prefer the approach in SLaks answer (sticking with asynchronous behavior). However, it does depend on your application. Exercise caution.
I would give the same answer as this jquery json populate table
This code will give you a little idea how to use callback with loops and ajax. But I have not tested it and there will be bugs. I derived the following from my old code:-
var processCnt; //Global variable - check if this is needed
function formSubmit(){
var lines = $('#urls').val().split('\n');
$.each(lines, function(key, value) {
$('#dlTable tr:last').after('<tr><td>'+value+'</td><td>Not Started</td></tr>');
});
completeProcessing(lines ,function(success)
{
$.ajax({
url: 'process.php?id='+value,
success: function(msg) {
$('#dlTable').find("tr").eq(key+1).children().last().replaceWith("<td>completed rip</td>");
}
});
});
}
//Following two functions added by me
function completeProcessing(lines,callback)
{
processCnt= 0;
processingTimer = setInterval(function() { singleProcessing(lines[processCnt],function(completeProcessingSuccess){ if(completeProcessingSuccess){ clearInterval(processingTimer); callback(true); }})}, 1000);
}
function singleProcessing(line,callback)
{
key=processCnt;
val = line;
if(processCnt < totalFiles)
{ //Files to be processed
$.ajax({
url: 'status.php',
success: function(data) {
$('#dlTable').find("tr").eq(key+1).children().last().replaceWith("<td>"+data+"</td>");
processCnt++;
callback(false);
}
});
}
else
{
callback(true);
}
}

Categories

Resources