I have an asp.net page that loads a chart and some tables.
When the page loads I retrieve some data from a server & make a few ajax calls as shown in the code below.
I have two global variables, RainFall and RainDates that I need to populate.
When the page loads I have a function CalcSummaryStats that makes use of these global values to calculate some statistics.
My understanding (AJAX & Jquery are new to me) is that the ajax requests run asynchronously so the $.ajax method returns before the request is finished, and therefore before the success callback runs.
So after some reading I could use $.when method like the line below,
$.when(methodRainCont(), methodRainSingle()).then(calcData);
In methodRainCont the chart is draw and in this function at the same time RainDates is populated.
In methodRainSingle my other global variable is populated.
And my understanding is that this means that once both methods have finished running (assuming that includes the success callback) my function calcData is then called. calcData calls another function outside of the $(document).ready block called CalcSummaryStats & this is where my error happens.
It tries the line below
var cM = RainDates[0].getMonth();
but get this error
jQuery.Deferred exception: Cannot read property 'getMonth' of undefined TypeError: Cannot read property 'getMonth' of undefined
So it seems like RainDates is not populated? I thought using $.when would make sure both functions had run successfully before calling calcData?
My JS file
// my two global variables
var Rainfall = [];
var RainDates = [];
$(document).ready(function () {
var $opts = $('#optList');
$.ajax({
type: 'GET',
url: 'api/UserOptions',
dataType: 'json',
success: function (codes) {
$.each(codes, function (i, code) {
$opts.append('<li id="' + code + '">' + code + '</li>');
});
},
error: function () {
alert("Error ");
}
});
function methodRainCont() {
$.ajax({
type: 'GET',
url: 'api/RainContr',
dataType: 'json',
success: function (data) {
DrawChart(data);
},
error: function () {
alert("Error");
}
});
}
function methodRainSingle() {
$.ajax({
type: 'GET',
url: 'api/RainSingle',
dataType: 'json',
success: function (data) {
Rainfall = data; // setting my global variable values
},
error: function () {
alert("Error");
}
});
}
$.when(methodRainCont(), methodRainSingle()).then(calcData);
function calcData()
{
var cords = {
x: {
min: RainDates[0],
max: RainDates[RainDates.length - 1]
}
};
CalcSummaryStats(cords);
}
});
Your functions methodRainCont() and methodRainSingle() do not return a promise to be used by $.when(), so calcData() executes immediately and ajax calls are not finished.
So, inside these functions, replace$.ajax({ with return $.ajax({
Related
I have a function that goes to a PHP script which returns the Server Operating System.
The script is literally dead simple:
<?php
echo (strpos(PHP_OS, 'Linux') > -1 ? 'Lin' : 'Win');
My goal is to be able to differentiate between operating systems so that I can declare a global path variable in my .js file for future uses.
This is what I've done so far:
function serverOS()
{
var os;
$.ajax({
url: '../scripts/ajax/detect-os.php',
type: 'get',
success: function(res)
{
os = res;
return os;
},
error: function(res) {alert('Major Error!'); console.log(res)}
});
return os;
}
console.log(serverOS());
The ending console.log outputs undefined - but if I console.log os inside of the success callback function, then it outputs what I expect.
According to this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
I should be able to do what I want with the above script but it doesn't seem to work. How do I go about setting and getting a global variable using ajax in JavaScript/jQuery?
AJAX operations are asynchronous. They will not block the rest of your JavaScript from executing.
The final return statement in your function attempts to return os immediately (before the AJAX operation has completed. Remove that return statement and in the success handler take care of all the logic to get the value back to the caller.
function serverOS() {
// The AJAX method will invoke the logging function no matter what.
// But, it won't happen until the AJAX call is complete.
$.ajax({
url: '../scripts/ajax/detect-os.php',
type: 'get',
success: function(res) {
returnValue(res);
},
error: function(res) {
alert('Major Error!');
returnValue(res);
}
});
}
function returnValue(val){
console.log(val);
}
serverOS();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Scott's Answer definitely works - but there does also seem to be an alternative I stumbled across. There's an AJAX property called async. Setting this to false in my function means it becomes a synchronous ajax call. Changing my function to this:
var os;
function serverOS()
{
$.ajax({
url: '../scripts/ajax/detect-os.php',
type: 'get',
async: false,
success: function(res)
{
returnValue(res)
},
error: function(res)
{
alert('Major Error!');
returnValue(res)
}
});
}
function returnValue(val)
{
os = val;
return os;
}
serverOS();
console.log(os); //this print Lin on my Linux machine.
ref: https://api.jquery.com/jQuery.ajax/
I'm trying to create a reusable function that will allow me to call an AJAX request and use one of the passed in parameters as an argument in the data section of the AJAX call.
// Returns AJAX data for updating other fields based on a dropdown changing
App.prototype.OnDropdownChange = function (s, e, newId, ajaxParameter, ajaxRequestURL) {
// Create an AJAX request based on the parameters
$.ajax({
url: ajaxRequestURL,
data: JSON.stringify({ ajaxParameter: newId }),
type: 'POST',
success: function (data) {
// Return the data
return data;
},
error: function (data) {
// Error
return data;
}
});
}
The "ajaxParameter" would, ideally, hold the name of the parameter being passed up. So for example, "ajaxParamter" contains "theNewID" which is what my MVC controller is expecting as a parameter however when it's passed up it is shown as "ajaxParameter" and not the value inside.
How can I get this working?
EDIT
http://imgur.com/a/GSaPd
See here how it shows as ajaxParameter? What I want is that to be whatever I pass it in as.
You can do what you require, you just need to build the object using bracket notation to define the key.
However a much larger problem is your use of return within the success and error handlers. As the AJAX request is asynchronous you cannot return anything from it. Instead you need to provide callback functions to be executed under those events. Try this:
App.prototype.OnDropdownChange = function (s, e, newId, ajaxParameter, ajaxRequestURL, sCallback, eCallback) {
var data = {};
data[ajaxParameter] = newId;
$.ajax({
url: ajaxRequestURL,
data: data, // note no need to stringify the object
type: 'POST',
success: function (data) {
sCallback && sCallback(data);
},
error: function (x, s, e) {
eCallback && eCallback(x, s, e);
}
});
}
You can then call that like this:
x.OnDropdownChange(s, e, contactID, "CustomerContactId", "/Project/Project/GetCustomerContactDetails/", function(data) {
// success:
console.log(data);
}, function(x, s, e) {
// error:
console.log(x, s, e);
});
As you can see from this code, it's still quite verbose and is essentially now just a wrapper for $.ajax with very little benefit.
First of all when you are passing an obj in the data paramater of $.ajax request you don't need to stringify it unless i presume that you are storing like a JSON string in a database.
Second you can't return the data provided by the success, error, beforeSend and complete callback functions of the ajax request as they are a function itself and you are just returning the data to the callback function itself.
To get the data from the callback function to your original function you need to use a temporary variable to store the data you need to return
var myAjaxDatavalue = (function(myMethod,myData,myUrl){
var temp = null;
$.ajax({
method: myMethod,
url: myUrl,
data: myData,
async: false,
success: function(result){
temp = result
}.
error: function (xhr, ajaxOptions, thrownError){
console.log(xhr);
}
});
return temp;
})();
but beware as you can see one of the purpose of ajax, which being an asynchronous will be disable. This may lead to problems if your getting an enormous amount of data.
Apologies if this is a duplicate question, I've followed some steps from another question which didn't seem to help me. I am trying to retrieve some JSON data, store part of the data into a variable and use that variable in a separate function outside of the AJAX request.
My expected response from the json data is http://localhost:8000/tutorials/retrieve/?page=2 (This response shows if I log the variable inside of the AJAX code) however the actual response I get when I try to log the variable from another function is as follows:
n.Event {originalEvent: MouseEvent, type: "click", timeStamp: 1436727171161, jQuery21304066238570958376: true, toElement: div#loadmore.recentTutorials…}
Here is the current code
var recentFirstPage = '';
function retrieveTutorials(){
$.ajax({
type: "GET",
url: "/tutorials/retrieve",
dataType: "json",
success: function(data){
**some unrelated parsing code here**
//Set the variable to what I need
recentFirstPage = data.next_page_url;
},
error: function() {
alert("An error occurred processing AJAX request.");
}
});
}
$('#main-content-wrap').on('click', '.recentTutorials', function(recentFirstPage){
//Does not return expected result
console.log(recentFirstPage);
});
When I click .recentTutorials I expect the console to log the data from JSON however it doesn't. Can someone help clear up my error(s)?
The reason that it doesn't log the data from JSON s that the call is asynchronous. This means that the function will execute top to bottom without waiting for the call to finish.
One method that's used is to leverage deferred objects which return a promise on completion. You can accept an anonymous function to the invoker function so that it's call back is executed within the scope of the click.
Observe:
function retrieveTutorials(){
return $.ajax({
type: "GET",
url: "/tutorials/retrieve",
dataType: "json"
});
}
$('#main-content-wrap').on('click', '.recentTutorials', function(){
//store our function call as an ajax promise
var promise = retrieveTutorials();
//wait for the ajax to return so we can mutate the data
promise.done(function(data){
//now our data will be properly
recentFirstPage = data.next_page_url;
});
});
It seems to me that you are trying to log the data before the ajax is completed. It`s better to use deferreds . Try this:
function retrieveTutorials(){
return $.ajax({ // will return deferred object
type: "GET",
url: "/tutorials/retrieve",
dataType: "json",
success: function(data){
**some unrelated parsing code here**
//Set the variable to what I need
recentFirstPage = data.next_page_url;
},
error: function() {
alert("An error occurred processing AJAX request.");
}
});
}
$.when( retrieveTutorials() ).done(function ( data ) {
console.log(recentFirstPage);
});
The parameter in your click handler is the last and final nail in your coffin. It's always the jquery event and you shouldn't handle it at all.
You do need to call the retrieveTutorials() function within the handler and you need to pass it a callback function that will be executed on success. So your retrieveTutorials() function will look something like this:
function retrieveTutorials(success){
$.ajax({ type: "GET", url: "/tutorials/retrieve",
dataType: "json",
success: success,
error: function() { alert("An error occurred processing AJAX request.");
} }); }
And your click handler:
$('#main-content-wrap').on('click', '.recentTutorials', function(){
retrieveTutorials(function(data){
console.log(data.next_page_url);
});
});
You can also use all the promise based goodness in the other anwers, but the above would be an idiom you'll see again and again.
I have a jquery ajax code as following:
$(document).ready(function() {
var global_arr = new Array();
$.ajax({
url: 'result.php',
type: 'post',
dataType: 'json',
success: function(data) {
$.each(data, function(key, value) {
global_arr.push(value.name);
});
alert(global_arr); //get correct value, works fine
}
}); //end of ajax function
alert(global_arr); //get null, it doesn't work properly
});
Notice the lines to alert global_arr, why I can't get the value out of $.ajax() function?
Thanks anyone help on this.
Ajax takes time to complete. The function execution does not take nearly as much time. So by the time you get to your alert outside of the ajax request, the ajax request is still using time to complete (either in transmission or in server side actions).
You can always wait for the ajax method to be complete.
$(document).ready(function() {
var global_arr = new Array();
var complete = false;//flag to wait for ajax completion
$.ajax({
url: 'result.php',
type: 'post',
dataType: 'json',
success: function(data) {
$.each(data, function(key, value) {
global_arr.push(value.name);
});
alert(global_arr); //get correct value, works fine
complete = true;//mark ajax as complete
}
}); //end of ajax function
(function runOnComplete(){
if( complete ){//run when ajax completes and flag is true
alert(global_arr);
}else{
setTimeout(runOnComplete,25);//when ajax is not complete then loop
}
})()
});
However, the most common way is to use a callback.
$(document).ready(function() {
function runOnComplete(){//code executes once ajax request is successful
alert(global_arr);
}
var global_arr = new Array();
$.ajax({
url: 'result.php',
type: 'post',
dataType: 'json',
success: function(data) {
$.each(data, function(key, value) {
global_arr.push(value.name);
});
alert(global_arr); //get correct value, works fine
runOnComplete();//callback
}
}); //end of ajax function
});
Ajax is asynchronous. At the time the JS engine reaches your non-functioning alert() line, the AJAX call has not yet had a chance to get a response from the server and set the variable.
That's why the inner alert() works. It gets executed when the response comes in from the server.
Ajax function runs asynchronously and before ajax function adds incoming data in your array, the outer alert function runs and for this reason alerts an empty array.
You can use async-await to make the outer alert function wait for the incoming data.
$(document).ready(async function() {
var global_arr = new Array();
await $.ajax({
url: 'result.php',
type: 'post',
dataType: 'json',
success: function(data) {
$.each(data, function(key, value) {
global_arr.push(value.name);
});
alert(global_arr);
}
}); //end of ajax function
alert(global_arr); //it will work fine now
});
that is because alert(global_arr); //get null, it doesn't work properly runs before $.ajax has completed
My suggestion here would be to break this out in to 3 funcitons so it will make a bit more sense. You will need ajax, handelRequest, onComplete.
You may also want to add and error handler to your ajax function so if it does fail it can do so with out the script locking up on the user.
$(document).ready(function () {
var global_arr = new Array();
$.ajax({
url: 'result.php',
type: 'post',
dataType: 'json',
success: handelRequest(data),
error: handleError
});
function handelRequest(data) {
$.each(data, function (key, value) {
global_arr.push(value.name);
});
onComplete(global_arr); //get correct value, works fine
}
function onComplete(global_arr){
// then here you can do what ever you
// you would like with the array
alert(global_arr);
}
function handleError(){
// gracefully fail
}
})
I'm creating a program that gets data from a server using AJAX/JSON and then used that data to draw onto a canvas (html5). I have a function that when called, does some initialization and then calls this function:
function getClimateData(climateElement) {
$.ajax(
{
type: "GET",
contentType: "application/json; charset=utf-8",
url: "/Climate/yearInformation" + climateElement,
data: "{}",
dataType: "json",
success: function (data) {
weatherData = data;
},
error: function (xhr, err) {
// Note: just for debugging purposes!
alert("readyState: " + xhr.readyState +
"\nstatus: " + xhr.status);
alert("responseText: " + xhr.responseText);
}
}
)
};
The problem is that before all the data has arrived, the calling function continues and draws some stuff on my canvas, based on the data (which isn't there). This only happens sometimes.
How can I make sure the data has arrived before execution continues ?
Do the work…
success: function (data) {
weatherData = data;
// <------------------ HERE!
},
… and not in the calling function.
That is the point of having a callback function.
Move the code that draws based on the data to a separate function call in the success function - or just put the code directly in the success function.
...
success: function (data) {
// use data to do your drawing
},
...
It is theoretically possible to put the request into synchronous mode using async: false but it's usually a bad idea.
The best way to deal with this is to change your script's structure so everything dependent on the request happens in the success callback (or gets called from there).
You should put the drawing function in your success callback. This way, the drawing functionality is only triggered when the data arrives.