jquery function with variable problem - javascript

I'm trying to return a list of select options to a JqGrid Add feature.
I have a javascript/jquery function that does a GET to get a string preformatted to work with JqGrid. I'm having trouble returning the results to the JqGrid though. How do I return the data from the jQuery Get function?
function getDealerPoolSelectOptions() {
var selectOptions = "1:A;";
$.get("DealerManagement/GetAllDealerPoolCodes", function(data) {
alert("Data: " + data.toString()); //Displays all the data I'm looking for
selectOptions = data;
});
alert("SelectOptions: " + selectOptions); //Just Displays the 1:A
return selectOptions;
}

$.get begins an asynchronous AJAX request and calls your callback function(data) ... once it is done. $.get itself returns before the request is complete. The alert("SelectOptions ...") part runs immediately (before the data is retrieved) so selectOptions isn't set yet.

jQuery ajax, by default, makes an asynchronous request (meaning it will make the request in the background, without blocking execution in the rest of the function).
EDIT: While you can make synchronous requests, I should note that this is very discouraged. Instead, you should design your code in a way that takes advantage of event driven programming.
You can make a synchronous request like this:
function getDealerPoolSelectOptions() {
var selectOptions = "1:A;";
$.ajax({
async: false,
url: "DealerManagement/GetAllDealerPoolCodes",
success: function(data) {
alert("Data: " + data.toString()); //Displays all the data I'm looking for
selectOptions = data;
}
});
alert("SelectOptions: " + selectOptions);
return selectOptions;
}

Probably you should describe your original problem. What you want to do with jqGrid?
Do you want to fill select of edit or search field with the data from the server? You should use dataUrl of the editoptions or the searchoptions. The feature (dataUrl) are introduced exactly for loading the data per ajax.
If the data which you can provide from the server can be only JSON and not in the format which are waiting by jqGrid you can use buildSelect additionally to reformat the data returned from the server. For more information see my old answer.

The alert gets called before the selectOptions = data; because ajax functions are called asynchronously. If you want something to happen, like adding the data to a grid, call it in the get callback after you set the selectOptions data.

Related

Javascript scope problems and confusion

I know scope should be simple. I can see that when going through the documentation on scoping, and when reading responses to the other people who've asked this here. That's why I'm confused. Here's the relevant chunk of code I'm working with:
$.ajax({
type: "GET",
url: locationURL,
success: function (result) {
console.log(result);
var output = "<table><thead><tr><th>ID</th><th>Subject</th></thead><tbody>";
for (var i in result.messages) {
var id = result.messages[i].id;
var locationURL = "https://www.googleapis.com/gmail/v1/users/me/messages/" + id + "?access_token=" + token;
var subject = "test";
$.ajax({
type: "GET",
url: locationURL,
success: function (result) {
subject = result.payload.headers[0].name;
console.log(subject);
}
});
console.log(subject);
output += "<tr><td>" + id + "</td><td>" + subject + "</td></tr>";
}
output += "</tbody></table>";
display.html(output);
$("table").addClass("table");
}
});
As you can probably tell, I am working with the Gmail API. So what am I doing here? The first ajax call is getting the list of all message ids. Then, for each message id I need to request message details, hence the nested ajax calls.
Now, the confusing part is this: In the outer ajax call's success function I define var subject = "test". I intend to overwrite this with the subject line from each message. Before I specifically look for the subject line in the payload of the message details, I just want to get some new string instead of test. In the success function on the nested ajax call I set subject = result.payload.headers[0].name; and the subsequent 'console.log(subject)' shows me that var subject has a new value. However, back in the outer ajax, when I add the next id and subject to my table, the value of subject still tests.
I would appreciate any pointers, thanks!
"Ajax" stands for "Asynchronous JavaScript and XML", meaning it's asynchronous. So whenever you call $.ajax, that code runs at the same time as the code right after that ajax call. This can be very useful, but also quite annoying in situations like yours where there's stuff outside the ajax call that depends on the data from the Ajax call. Typically this is what the success function is used for.
If you want a quick and dirty fix, you could add async:false as a key:value pair in your ajax call, although this is heavily frowned upon because it ruins the asynchronous power of ajax.
See this answer for information on how to make asynchronous ajax calls inside for loops work.

Aborting / canceling running AJAX calls before execute new AJAX in JS

I've never done this type of manipulation of AJAX calls (to stop/abort/cancel or ignore? already running AJAX calls before the execution of a new one) before so I really don't understand how to do that and would appreciate some direction.
I have a page in my app where I make a number of AJAX calls to fill dynamically the data in my table (Object Name, Object Fit, Object Progress) when the page loads. For example, there are 5 rows in the table. So I call
$.post("/getFit", {objectId: objectId}, function (result) { manipulation with result }
and
$.post("/getProgress", {objectId: objectId}, function (result) { manipulation with result }
5 times each in the loop -- one for each of the objects.
The first column of my table has links to more detail on the object, and clicking on them I call another AJAX:
$(document).off('click', '.js_object').on('click', '.js_object', function (e) {
var objectId = $(this).attr("id")
$.post("/viewObject", {objectId: objectId}, function (result) {document.getElementById("main_window_content").innerHTML = result; });
})
The problem is that the browser will not render the results of the last AJAX call (/viewObject) until it has received the results of all of the previous calls (/getFit x5 and /getProgress x5).
As a result, a user that wants to drill into the detail on an object needs to wait until the AJAX calls for the other objects are complete before they see anything.
So I struggle with how to stop/abort/cancel (or ignore?) "/getProgress" and "/getFit" so we can fully execute "/viewObject" and view the results of it.
I would very much appreciate your help.
Use xhr.abort() to kill the xhr requests as shown in the below code in JS. I believe there is ajax.abort(); in JQuery
var xhr = $.ajax({
type: "POST",
url: "XXX.php",
data: "name=marry&location=London",
success: function(msg){
alert( "The Data Saved: " + msg );
}
});
//kill the request
xhr.abort()
If you want execute one ajax after another, and you need all requests to work to show the final result, you can use .done():
$.ajax({
url:'/getFit',
data:{objectId:objectId}
})
.done(function(data){
//do something with the results then call /getProgress
$.ajax({
url:'/getProgress',
data:{objectId:objectId}
})
.done(function(data){
//do something with the results then call /viewObject
$.post("/viewObject"....
})
});
That way you only show /viewObject if the others calls were successfull

Restrictions of Multiple AJAX Calls?

Context:
I have a javascript file, within i have an AJAX function calling a php file returning the data and performing a function with it(an sql query returning records for a set date, then plotting it on a map using the google maps API). Lets call this Data A
Question:
What i need is to be able to get the next days data and storing it in an array (Lets call it Data B) and comparing it with the first set of data(Data A).
From my understanding i need another ajax call within this one, iv tried it but it seems i cannot get the data, i may have a misunderstanding of the core workings of ajax. For example:
var data_a;
var data_b;
$.ajax({
type: "POST",
url: scriptday,
data: $("#dayForm").serialize(),
error: function( data ) {
console.log("Error: "+ data );
},
success: function( json ) {
data_a = json
//start of inner ajax call
$.ajax({
type: "POST",
url: scriptday2,
data: $("#dayForm").serialize(),
error: function( data ) {
console.log("Error: "+ data );
},
success: function( json ) {
data_b = json
// access data_a here
}
}
});
//end of inner ajax call
}
});
EDIT:
Correct way of doing this was to store inner ajax call in a function that takes data_a inside.
function innerAjax(data_a){
$.ajax({
.....
//data_a can now be used here
})
}
and to call it inside the first ajax as
innerAjax(data_a);
this way using AJAX in a synchronous way :)
thanks to those who contributed!
No, restrictions of multiple AJAX calls do not exist, if you use async ajax (and looks like you do).
For you problem - perhaps you need to wait correctly for result of both ajax calls, to store the results and then process them.

JSON JS Array of Objects from Facebook FQL Function

I've been pulling my hair out with this function. It's a function within a function which is why I think it's not returning anything, heres the code:
function getEventImageNormal(data) {
$.getJSON("https://graph.facebook.com/fql?access_token=" + access_token + "&q=SELECT pic FROM event WHERE eid=" + data, function(data){
console.log(data.data[0].pic);
return data.data[0].pic;
});
}
The correct item, the URL of the image, is being set to the console log, but not being returned?
If anyone is wondering why I'm not using https://graph.facebook.com/object_id/picture to get the events image, it's because this functionality is currently not working and the only method is to use FQL for event images.
By default getJSON() performs asynchronous call.
You can call a function right within the success callback handler to treat the response.
$.getJSON("https://graph.facebook.com/fql?access_token=" + access_token + "&q=SELECT pic FROM event WHERE eid=" + data, function(data){
console.log(data.data[0].pic);
getResponse(data);
});
function getResponse(data) {
// handle your data here.
}
You need to add callback=? parameter to your url to let remote url and jQuery know it is a jsonp call. If it is only json sent, it is against cross domain security policies and browser won't accept it into the DOM.
This is in addition to processing the data within the sucecss callback of request, due to asynchronous nature of ajax.
var data=/* your value*/
$.getJSON("https://graph.facebook.com/fql?callback=?&access_token=" + access_token + "&q=SELECT pic FROM event WHERE eid=" + data, function(data){
/* process data here*/
})

Iterate on array, calling $.ajax for each element. Return array with all ajax results

I've just started working with JavaScript for non-trivial things, so this is probably straightforward...
What I'm trying to accomplish: iterate on an array of product references, fetch the JSON for each reference, and return an array of all the product information (with a hash-like structure indexed by reference).
What I've tried:
function fetchProductData(references){
var product_data = new Object();
references.forEach(function(ref){
$.ajax({
url: "http://localhost:3000/products/find.js?reference=" + ref,
dataType: "jsonp",
type: "GET",
processData: false,
contentType: "application/json",
success: function(data) {
product_data[ref] = data;
}
});
});
alert('before return: ' + product_data);
return product_data;
};
$(document).ready(function(){
var products = fetchProductData(references);
alert('products : ' + products);
});
Here's what I don't understand: the first time I call alert to display the array contents, the array is empty. However, on the second call, the array is populated with the data I want.
In other words, the "products :" alert displays the data I want in the code above. But if I comment the "before return: " alert, it no longer does. Why is this?
So my question is: how can I have jQuery make several $.ajax call to fetch product information, collect that information in an array, and return that array so I can use it elsewhere in my code?
Also, why is the data in the variable magically accessible after it is referenced in an alert?
The "A" in "AJAX" stands for "asynchronous" :). Your program doesn't wait for the call to complete before going on to the next iteration, meaning you'll probably not get all of your data. Also the alert has the same problem. Operation to concat 'before return:' to the string add just enough time to get some data in the variable. On a faster machine you might find you never get data.
I think you really need to rethink your approach. It's not a good idea to have multiple AJAX requests in a loop. It will greatly increase latency of the page. Pass all your parameters once using JSON, then have your server side script loop through that and return a single response in JSON.
function fetchProductData(references){
// make sure your "references" is a JSON object
$.getJSON('http://server/side/url', {'json':references}, function(product_data) {
// do something with product_data (alert them, put them in an array, etc)
});
}
function fetchProductData(references, cb){
var length = 0;
var product_data = new Object();
references.forEach(function(ref){
length++;
$.ajax({
url: "http://localhost:3000/products/find.js?reference=" + ref,
dataType: "jsonp",
type: "GET",
processData: false,
contentType: "application/json",
success: function(data) {
product_data[ref] = data;
if (++count === length) {
cb(product_data);
}
}
});
});
};
$(document).ready(function(){
var products = fetchProductData(references, function(products) {
alert('products : ' + products);
});
});
Use a callback on your asynchronous operation.
The reason it appears to work with the alert call is because alerting a message gives ajax enough time to populate your array. The return statement is only triggered after you click OK on the alert box giving your code a window of 250ms to populate the array with data.
You are executing you ajax query in async mode. And you want a sync result. Try to add:
async: false
Hope this helps.
your $.ajax call is asynchronous, so what is happening is that the first time you make the call, your javascript makes the call, moves on to the next line (alert) and then loops. You're data hasn't returned at that point yet. What you can do to remedy this is to set the async: false option in your $.ajax call.
This is an asynchronous operation. The only sure way to know when the data is ready is in the callback function: success: function () {...}, which gets called when the data has finally returned. Put your alert in there.

Categories