Multiple ajax calls in jquery - javascript

I am using jquery for my project.
I have the following requirements:
I need to make a function call which invokes 5 other functions.
These 5 functions are ajax calls which work independent of each other. The ajax calls get data from server and appends values to a global object.
I am facing difficulty in finding whether all the ajax calls are done or not. After all the calls are done , I have to set it to localStorage and then load another html file.
What is the best way to do it?

If the number of ajax calls made are constant,You can use the following logic
COUNTER=5;
function reduceCounter(){
COUNTER --;
if(COUNTER == 0)
{
localStorage.Obj=JSON.stringify(Obj);
location.href="nextPage.html";
}
In each of your ajax calls , call reduceCounter() at .always();
eg:
$.ajax({
url: ..
type: 'GET',
dataType: 'json',
})
.done(){...
//set Obj
},
.fail(){...
},.always(){
reduceCounter();
}

mmm... Is it something you can do with jQuery Load, it makes sure everything loaded before you call any function or anything:
$(document).ready(function() {
//Make sure all DOMs loaded!
}):

Related

Array contents don't change when used in a function in AJAX success

I'm using AJAX to parse json, everything works fine although when I try to call a function where I pass on the index value of the loop and then the funcion pushes this value into the Global array, It seems like it's not pushing these values even though console.log() prints out everything as it should on each step yet when I check the array length it's always at 0.
//This bit of code is actually inside a function and another ajax success
$.each(updatedData, function(index, element) {
$.ajax({
type: 'GET',
url: 'https://en.wikipedia.org/w/api.php?action=query&prop=extracts&exintro&explaintext&format=json&redirects&callback=?&titles='+updatedData[index],
data: { get_param: 'value' },
dataType: 'json',
success: function (data) {
console.log('success wiki');
//getting the pagenumber key value to use the extract value from it
var pagenum = Object.keys(data.query.pages);
if(data.query.pages[pagenum[0]].extract == null)
{
recycleData(index);
}
}
});
});
//this is the function which should push the trash value to the trashData
//the console.log actually logs all the correct values yet still doesn't push
function recycleData(trash){
console.log("sliced - "+trash);
trashData.push(trash);
}
//that's how the array is defined, it's obviously defined before all the functions just in case someone would ask
var trashData = [];
UPDATE: I have tested the array length after a delay, it is being populated after all the ajax requests have been completed yet I need other requests to wait for this request to finish so that the other requests will use updated data. This request is in another ajax success so keep that in mind.
If you want do other ajax on completion you can call your next ajax call on done function of previous ajax.
$.ajax({ ... }).done(second_ajax_fn);
Also you can set async:false but it is not recommended
The issue is likely that you're checking the value of trashData before the actual async requests are complete. If you want to ensure that all the requests are complete and then check it (or make more requests), you need something like jQuery Deferred - waiting for multiple AJAX requests to finish.

Javascript functions wrong sequence

I am calling a function that loads JSON from a server and displays it in a div, that gets dynamically created in the DOM. After the created div is displayed, I want to do other stuff like parent.appendChild(x). Now it sometimes happens that the second step gets run before the first. I've tried to use this code, but it doesn't seem to work.
$.ajax({
url: firstfunction(),
success: function() {
parent.appendChild(x)
}
});
Note that firstfunction() loads JSON and displays it inside a newly created div.
Any ideas how to fix this problem?
You should use promises, so you wait to finish your Ajax request before moving on to another task (for your example manipulate DOM).
async function doAjax(ajaxurl){
const result = await $.ajax({
url: ajaxurl
});
return result;
}
//Call function
doAjax().then( data => doStuff(data) )
Async/Await with $.ajax example:
https://codepen.io/anon/pen/xpzJza
I fixed the problem by just using a synchronous httprequest.

consolidating $.ajax

I have several ajax call on my page and I want to consolidate them into one function.
For now I have this type of function in several places:
function AjaxCallOne () {
//do something
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: TheURL,
data: "{'TheData':'" + JsonData + "'}",
dataType: "json",
cache: "false",
success:...
error:...
});
}
I want to write a single function that'll be used for all ajax calls like this:
function MyGeneralAjaxCall(TheData, TheURL, TheSuccessFunction, TheErrorFunction) {
$.ajax({ .... });
}
My question is this: if I do that and the user send two ajax calls, almost simultaneously, to the point where the second ajax call is made before the returning data of the first call comes back, will the success or error functions trigger for the the correct call. I'm worried that the success function that'll be executed won't be for the proper ajax call if the user triggers a second call before the first one is returned.
Thanks.
Your approach will work as you expect. Each success function, etc., that you pass in will be used individually by each associated AJAX call. (All of your parameters will be kept together.)
First, There's no single, global set of callbacks for ajax requests. Each ajax invocation gets it's own set of callbacks.
Secondly: $.ajax({...}) is your MyGeneralAjaxCall... if you are thinking you need a set of default options, a better way would be to set up a
var defaultoptions = { type: "POST", ...} //put default options, mimetypes, etc, here
(or something that returns that) and then wherever needed do:
var myajaxoptions = $.extend({},defaultoptions,myoverrides);
$.ajax(myajaxoptions);
That's much more extensible. No need to make up "men in the middle". Your approach will work, but I could easily see more than one MyGeneralAjaxCall being created. If you can manage not creating 5 or more methods like that MyGeneralAjaxCall, I suppose you'll be doing ok, but it could get nasty real quick.

jQuery Async Issue, Variable Assignment After GET Request

I'm sure the solution is staring me right in the eyes, but I just cannot see it. I am trying to load an object from an outside file source. I've tried it several which ways using jQuery's built in methods, but keep returning undefined. Is my issue the scope? I need partnerData right where it is because of other dependent methods in my script. I don't want to operate the rest of my site's functions from within the $.get callback. Any help is greatly appreciated, here's the code:
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
});
console.log(partnerData); /* returns undefined instead of object */
});
EDIT:
Thanks for all the feedback everyone. This is the solution I went with:
var partnerData;
$.ajax({
url: 'data/partners.json',
dataType: 'json',
async: false,
success: function(data) {
partnerData = data;
}
});
The reason why you're seeing undefined is because ajax requests are asynchronous by default. This means your get method gets invoked and the code flow moves down to the next statement while the request executes in the background. Your callback function is later invoked when the request completes.
Using callback functions is a common pattern used in situations like this. But you seem to be saying you don't want to do or can't do that. In that case, you could use async: false which would force the request to be synchronous. Keep in mind however, that your code will be blocked on the request and if it's a long-lived request, the user experience will degrade as the browser will lock up.
P.S. You shouldn't need to parseJSON - if response has the correct mime-type set, jQuery will intelligently guess the type and parse the JSON automatically. And in case the server isn't sending back the correct mime-type, you can also explicitly tell jQuery what the expected return data type is; see the dataType argument to $.get() .
One way you might modify your code, to force synchronous requests:
$.ajax({
type: 'GET',
url: 'data/partners.json',
success: function(file){
partnerData = $.parseJSON(file);
//ideally you would perform a callback here
//and keep your requests asynchronous
},
dataType: 'json',
async: false
});
function is proccessed to the end event when ajax is still being proccessed. insert it into callback function
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
console.log(partnerData);
});
});
I would say that your problem is the same of the one that I just solved, if $.get is AJAX! and it is setting a variable, to read that variable outside the callback you need to wait the response! So you have to set async=false!
console.log in synchronous and get is async.
try:
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
test();
});
function test(){
console.log(partnerData);
}
});

jQuery: insert html with javascript, waiting for it to run

I'm using $.ajax method to pull some html code and insert it into a 'div.listbox' element, using $('div.listbox').html() method.
I'm aware that .html will insert all HTML code, and execute all javascript code found under the HTML code.
What is actually happening:
$.ajax({
async: false,
url: 'ReturnSomeDataAsJSON',
data: {some_needed_data},
dataType: 'json',
success: function(data){
$('div.listbox').html(data.body)}
})
This data.body has a javascript that will make a call to an asynchronous function that will update an element inside the HTML under data.body.
Putting a .live function on the 'div.listbox' element, in order to listen to DOMNodeInserted event, I could see that the javascript method executed by the $...html(data.body) call updated 'div.listbox' element 6 times.
As this number could change, I can't just treat this as my solution, waiting to the element to change 6 times and then do what I want.
So I'm asking if it's possible to wait untill all javascript inside that .html call is executed before continuing to other javascript methods after the $.ajax call.
The only way would be to use a callback function inside your ajax-generated javascript, so you'd have:
//(ajax generated code)
<script>
...
$('div.listbox').css("color", "blue"); //For example, let's assume this code executes asynchronously
div_changed(); //This is the callback function
</script>
Then, in your main script you should have:
$.ajax({
async: false,
url: 'ReturnSomeDataAsJSON',
data: {some_needed_data},
dataType: 'json',
success: function(data){
$('div.listbox').html(data.body)
}
})
function div_changed(){
//Here put the code you want to be executed after changes are made
}
This is the only way, note that this is asynchronous.
Hope this helps. Cheers
JavaScript is a functional programming language meaning that you almost everywhere work with functions and can also pass functions as parameters. Let's describe your scenario: In scope A (parent element) you want to do something, but just when in scope B (child element) something happens and finishes. Only scope A knows what it wants to do, and only scope B knows when it finishes its job. So what do you do? Here are some solutions:
Hardcoding your logic of scope A in scope B (spaghetti code)
Get the function back from scope B and execute it in scope A (bad idea)
Pass the logic of scope A as a function to the scope B and let B be the agent to decide when to execute that.
The best method is the third item and this is the spirit of functional programming.
Solve by adding a listener to DOMSubtreeModified event, by doing:
$.ajax({
async: false,
url: 'ReturnSomeDataAsJSON',
data: {some_needed_data},
dataType: 'json',
success: function(data){
external_data = $(data.body)
var data_html = $(data.body)[0]
var data_script = $(data.body)[1].text
listbox_container = $('form#main_form div.listbox-container:nth(0)')
//fill body
listbox_container.html(data_html);
// attach listener
listbox_container.live('DOMSubtreeModified', check_listbox)
// eval script
eval(data_script)
// this script will (some time, asynchonously) update listbox_container
// by adding some data, that I need to deal with
}
})
function check_listbox() {
listbox_internal_ container = $('form#main_form div.listbox-container:nth(1)')
if (listbox_internal_container.length >= 1) {
// do what I want (deal with new data filled),
// because internal container (that will be created
// by the $.ajax call) now exists with some data filled by the
// eval(...) of the script
};
}

Categories