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.
Related
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
So I have a peculiar issue with my AJAX request. When I make the request, I can click on the network tab and see the response, which is valid JSON. But when I try to use that data in my success function of the ajax call, it returns undefined. I'll post some pics of my console and network tab and some code.
And at last my code:
getWebinars: function (from, to, credential) {
$.ajax({
url: 'endpoint',
data: {
from: from,
to: to,
credential: credential
},
success: function (reply, status, xhr) {
console.log(reply);
var html = '<select class="webinars" multiple>';
for(var webinar_id in reply.list) {
html+= '<option value="' + webinar_id + '">' + reply.list[webinar_id] + '</option>';
}
html+= '</select>';
$('.modal-body').append(html);
}
});
}
I can't figure out for the life of me what the issue is here. I have tried everything I can think of. Logging the xhr, logging the responseJSON, setting the datatype to json. It's a simple get request and it's working, but the console doesn't seem to think so. Any help is appreciated.
ok, so I figured this one out, sort of. I should say "I fixed it" I still don't know why it did what it did. For whatever reason, jQuery was executing the success callback well before the request was complete, hence my undefined issue. I switched it over to good ol' vanilla javascript and it worked fine. As to why it happened with jquery, I don't have an answer for that. Hopefully this will help others out.
Your root cause is you don't mention dataType:'JSON' as parameter of your AJAX request.
So there is two ways to resolve your problem.
1.Add dataType parameter.
2.Parse the returned result using jQuery.parseJSON().
Solution 1
url: 'endpoint',
data: {
from: from,
to: to,
credential: credential
},
dataType:'text json'
solution 2
var obj = jQuery.parseJSON(reply);
alert( obj.list);
so I'm doing a basic assignment for uni, they asked us to use ajax and php to create a text input that validates the name and email plus a live search bar, all this without using db. So I have the html already set up, the .php with 3 different arrays with names, emails and news stored in and a main.js that already displays whatever you type in the text input in the console with the keyup event trigger. I just can't figure out a way to make an ajax request to compare what you type in to the info stored in the arrays.
In the arrays.php I have this :
*$classes = array('1' => 101, '2'=> 102, '3'=>103 );*
*$names = array('juan', 'tito', 'pedro', 'horacio', 'andres', 'cesar', 'nicolas');*
*$news = array('Title'=>array('El papa muere', 'Argentina gana el mundial', 'Fondos buitres cancelados' )'Noticia'=>array('noticia1', 'noticia2', 'noticia3')
);*
and in the main.js I have something like this:
$('#name').keyup(function(){
var name=$(this).val();
console.log(name);
that retrieves what I type in each text field. As far as I can remember, the prof wrote something like this to give us a hint:
$.ajax({
url: ' ',
type: ' ',
success:function(data){
}
}):
But I just can't figure it out so any help would be much appretiated!
The general idea is to pass the current value of the search box to your PHP script via ajax. Then in your PHP script, you would filter your options based on the current value passed to it and return a filtered response. The javascript would then take the filtered response and output it on the page.
People usually use JSON as a format for passing information between Javascript and PHP.
To give you a little better understanding what $.ajax does. It will make a request to your server and then process the results. The parameters specified do the following:
url: The URL to request
type: The format of the response (eg. text, xml, json, etc.)
success: A callback to be called when the response comes back from the response.
Also note that the A in AJAX stands for asynchronous. This is why you need to give the $.ajax function a callback. Due to the nature of HTTP, you make a request and the response can return right away or in 30 seconds or never. When the response returns the callback will execute. It is not linear. Therefore the callback can execute after code below the the $.ajax call depending on how long it takes for the response to come back.
Maybe take a look at the example below to give you a better idea of how to do this:
<?php
$names = array('juan', 'tito', 'pedro', 'horacio', 'andres', 'cesar', 'nicolas');
$result = array();
foreach($names as $name)
{
if (strpos($name, $_GET['name']) !== false)
{
$result[] = $name;
}
}
echo json_encode($result);
?>
And the javascript
$('#name').keyup(function() {
var name=$(this).val();
$.ajax({
url: '?name=' + name,
type: 'json',
success: function(data) {
console.log(data);
// add data to 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.
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.