setting and calling global var using ajax - javascript

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/

Related

Deferred exception after populating global variable from ajax method with $.when

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({

Nesting ajax requests makes code hard to read

I usually like to organize my code so that one function fires a bunch of other
functions, like this:
/**
* GET MESSAGES:
*/
$(function() {
$.ajax({
url: '/messages',
method: 'GET',
dataType: 'json',
success: function(messages) {
if (messages.length > 0) {
keyedMessages = keyFork(messages);
reversedMessages = reverse(keyedMessages);
crushedMessages = crush(reversedMessages);
getFriendships(messages, crushedMessages);
}
mail.template.airmail();
}
});
});
However, if I need to do a second Ajax request inside one of the nested
functions I can't return the data because of the scope of the Ajax request
and it makes my code inconsistent and hard to follow, sort of broken up all over the place. For example, if one of the functions
invoked above fires a second Ajax request for friendships anything I write
after that will be broken from the communication chain due to the request and it seems impossible to return anything:
/**
* GET FRIENDSHIPS:
*/
function getFriendships(messages, crushedMessages) {
$.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
filteredCrushedMessages.forEach(function(filteredCrushedMessage) {
mail.sidebar.builder.messengers(filteredCrushedMessage);
});
mail.snailMail.onload();
}
});
}
If I try to return the data it doesn't work. Consequently I'll have to
continue invoking functions inside the nested request, every time I need to make another nested ajax request it breaks the chain. This makes my
code very hard to read. Are there any solutions to this problem or is
code that uses Ajax requests just hard to read?
You could store the data on a DOM element, then use jQuery Custom Events to get it done.
There's even support for passing arguments to your event handler:
https://learn.jquery.com/events/introduction-to-custom-events/#naming-custom-events
If I try to return the data it doesn't work.
Not appear jQuery promise returned from either function at Question ?
Try utilizing return statement , $.when.apply(this, arrayOfPromises) to return array of jQuery promise object from getFriendships
function getFriendships(messages, crushedMessages) {
return $.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
mail.snailMail.onload();
return $.when.apply($
, filteredCrushedMessages.map(function(filteredCrushedMessage) {
return mail.sidebar.builder.messengers(filteredCrushedMessage);
})
);
}
});
}
// e.g.,
getFriendships(messages, crushedMessages)
.then(function success() {
console.log(arguments)
}, function err(jqxhr, textStatus, errorThrown) {
console.log(errorThrown)
})

Using JSON data retrieved via AJAX in separate function

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.

losing data when leaving scope

I'm programming something in javascript and at one point I make an ajax call
I store the data in an object literal but when I leave the scope I lose the data (even in my object literal)
I don't understand what is happening here
var menusView = {
menusRep: null,
init: function () {
this.menusRep = menusRepository;
this.getMenus();
},
getMenus: function () {
$.ajax({
url: 'data/voordeelmenus.json',
dataType: 'json',
success: function (data) {
menusView.menusRep.menus = data;
console.log(data);//console output: [object, object,...]
console.log(menusView.menusRep.menus);//console output: [object, object,...]
},
error: function (error) {
alert("error reading file: " + error);
}
});
console.log(menusView.menusRep.menus); //console output: []
}
}
var menusRepository = {
menus: []
}
I think I included al the code that matters
thanks in advance!
I believe this is due to the asynchronous nature of AJAX and how you're using it. The final console.log is firing before the AJAX call can complete, thus the data is not available when the console.log is made.
You have a few options as I see it. You can use the returned data in the success callback, use another method within the success callback that processes the returned data, or you can set async to be false to process the AJAX request in a blocking fashion.
$.ajax({
url: 'data/voordeelmenus.json',
dataType: 'json',
async: false,
success: function (data) {
menusView.menusRep.menus = data;
console.log(data);//console output: [object, object,...]
console.log(menusView.menusRep.menus);//console output: [object, object,...]
},
error: function (error) {
alert("error reading file: " + error);
}
});
you have basically 2 lines
$.ajax(...)
console.log(...)
the ajax line schedules an ajax call and a callback that will be called when the ajax call returns, but does not block: it is asynchronous.
After this has been scheduled, console.log is called but the menu has not yet been set. It will only be set later, when the ajax call returns.
Your ajax call is asynchronous.
So when your code execution reaches console.log(menusView.menusRep.menus);
At that time your object did not receive any data.
Put your console.log(menusView.menusRep.menus); inside success handler of ajax call
That
console.log(menusView.menusRep.menus); //console output: []
must be inside the ajax call because it is async. Otherwise it will always be empty
Edit : Keep in mind to call
menusView.init();
Otherwise menusView.menusRep will be null
Hope it helps,
Dan

node js : should be use alert to invoke the function?

i dont know what happen with my code..i have a Node.js that queries a MySQL db within the route and displays the result to the user. My problem is how do I run the queries and block until queries are done before redirecting the user to the page they requested?
if i add alert before call,function run normally and quick response..but if alert disable the function cant return any value,the function like freeze..
this user code to request value to nodejs
function fred(){ //request function from here to fblue
alert('fred called'); //if i disable alert,the function not return any value
get('id', function(datmovMar) {
var obj = JSON.parse(datmovMar);
var items = Object.keys(obj);
var output='';
items.forEach(function(item) {
output+=obj[item].something+'<br/>';
alert(output);
});
});
}
function get(id, callback) {
$.ajax('http://localhost:8000/' + id + '/', {
type: 'GET',
dataType: 'json',
success: function(data) { if ( callback ) callback(data); },
error : function() { if ( callback ) callback(null); }
});
}
and this code locate in node js
fblue(function(datmovMar){ //call function from here
res.write(JSON.stringify(datmovMar));
res.end('\n');
});
function fblue(callback){
var query = connection.query('SELECT something from table'),
pinMarker = [];
query
.on('error', function(err) {
console.log( err );
updateSockets( err );
})
.on('result', function( user ) {
pinMarker.push( user );
})
.on('end',function(){
if(connectionsArray.length) {
jsonStringx = JSON.stringify( pinMarker );
callback(jsonStringx);
}
});
}
i dont know why if alert disable the function cant run normally?
please help...
thanks
You're calling jQuery's $.ajax method which will create an asynchronous javascript request to your server.
This means that the control flow will continue right after you initiated the call to your server.
So you should not expect from fred() function to block until your request has been served, instead you need to rewrite your browser side javascript code in asynchronous way.
jQuery's $.ajax function by default runs asynchronously. That means the request won't be blocked while it's running, so subsequent lines of code will be immediately executed. With async calls, order of execution is not guaranteed.
You can 'cheat' a little bit here and specify the async option as follows:
$.ajax('http://localhost:8000/' + id + '/', {
type: 'GET',
dataType: 'json',
async: false,
success: function(data) { if ( callback ) callback(data); },
error : function() { if ( callback ) callback(null); }
});
That will force the $.ajax call to NOT return until it is completed. That's not really the JavaScript way of doing things, however, because you lose the efficiencies gained by asynchronous execution. As another KARASZI pointed out, you should write this asynchonously.

Categories