losing data when leaving scope - javascript

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

Related

Jquery ajax parametric callback and variable scope

I'm not so much pro in javascript variable scopes and got stuck with one question.
If i have function which dose ajax call and then call my callback
function doAjaxFunc(param, callback)
{
$.ajax({
type: 'GET',
url: '/some/url/'+param,
success: function(data){
callback(data);
},
dataType:'json'
});
}
function someCallback1(ajaxResp){
// DO someting 1
}
function someCallback2(ajaxResp){
// DO someting 2
}
// exec
doAjaxFunc(1, someCallback1);
doAjaxFunc(2, someCallback2);
As ajax is async and it can be that sever will process param=1 case longer then param=2 is it possible that someCallback1 and someCallback2 will process not their responses. I mean callback argument value will be somehow mixed ?
If possible give some explanation details in answer
I mean callback argument value will be somehow mixed?
No. The callbacks will be called in completely separate invocations within scope of the originating AJAX success handler. There will be no cross-contamination of the data from either request.
Also, just as an aside, you can change this:
success: function(data){
callback(data);
},
To just this:
success: callback,
Check this example , i hope it is some helpful to understand scope in JavaScript
var isFirstCall=false;
function doAjax(param)
{
if(!isFirstCall)
{
//for example after do ajax
var millisecondsToWait = 1000;
setTimeout(function() {
console.log(param);
}, millisecondsToWait);
}
isFirstCall=true;
console.log(param);
}
doAjax('first call');
doAjax('second call');

Uncaught TypeError: Cannot read property 'length' of undefined Javascript

I have been facing a problem of which I am unable to call a .length() method to a data array in javascript. The purpose is to be able to iterate through an array of date time string in order to convert them to date objects in javascript. Here is my code.
My data:
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"sales_time_axis": [
[
"2019-12-29T10:42:25Z"
],
[
"2019-12-23T03:13:03Z"
],
[
"2019-12-23T02:50:51Z"
]
],
The ajax call:
$.ajax({
type: "GET",
url: endpoint,
success: function(data) {
window.sales_time = data.sales_time_axis
},
error: function(error_data) {
console.log('error')
console.log(error_data)
}
})
The for loop:
var sales_time;
var date_array = []
for(i = 0 ; i < sales_time.length ; i++){
date_array.push(new Date(sales_time[i]))
}
console.log(data_array)
I have declared sales_time as a global variable , however I'm getting this error:
(index):179 Uncaught TypeError: Cannot read property 'length' of undefined
at (index):179
Your help will be greatly appreciated!
Probably you are facing an asynchronous variable assignment problem. Try to put the for-loop together with the success callback and iterates over the same sales_time variable that are being received on the callback parameter.
$.ajax({
type: "GET",
url: endpoint,
success: function(data){
var sales_time = data.sales_time_axis;
var date_array = []
for(i = 0 ; i < sales_time.length ; i++){
date_array.push(new Date(sales_time[i]))
}
console.log(data_array)
},
error: function(error_data){
console.log('error')
console.log(error_data)
}
})
you need to wait the ajax call first,since it is async
take a look at following link:
How to await the ajax request?
As others had pointed out, ajax is an async process. Anything outside of the ajax run synchronously, meaning it won't wait for your data to come. One way you can do this is by putting the iteration method as a callback inside ajax success method with the data as its argument.
$.ajax({
// SOME CONFIGS HERE
success: function(result){
iterate(result);
}
});
function iterate(data){
// Do your iteration here
}
Or if you insists on the global variable thingy, then you can do it like this
// Assuming all these are inside the same javascript file
var data = []; // Make this a global value inside your file
$.ajax({
// SOME CONFIGS HERE
success: function(result){
data = result.data;
iterate(); // Get data, then hit the iterate process
}
});
function iterate(){
// Do your iteration here
data.forEach(() => { // Some process in here });
}
This method will call on the iterate ONLY after the call has successfully finished. Don't try to call iterate outside the success method or you will for sure get an empty array.
Your mindset in writing code have to change if your flow depends on a promise to be finished first. You need to execute your next step only after the promise has resolved, not simply running it while the promise still not resolved.

setting and calling global var using ajax

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/

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.

Passing jQuery ajax value back to calling JavaScript function

I have a problem passing data from a JQuery ajax call back to the calling location. The code in question is below:
jQuery("#button").click(function()
{
for(var i = 0;i < data.length; i++)
{
result = updateUser(data[i]); //result is not populated..
alert(result); //prints 'undefined'
}
});
function updateUser(user_id)
{
jQuery.ajax({
url:"/users/update/"+user_id,
type:"GET",
async: false,
success: (function(data){
//if I alert "data" here it shows up correctly
//but if i try to return it like below
//it does not get passed correctly
return data;
})
});
Any pointers are greatly appreciated
You cannot return value from an AJAX success handler like that. AJAX is asynchronous so execution will proceed to the next line where result is undefined. The only way you can get data back from an asynchronous operation is to use a callback. A callback is a function that gets called when the asynchronous operation finishes what it is doing:
jQuery("#button").click(function () {
for (var i = 0; i < data.length; i++) {
updateUser(data[i], function(result) {
alert(result);
});
}
});
function updateUser(user_id, callback) {
jQuery.ajax({
url: "/users/update/" + user_id,
type: "GET",
success: callback
});
}
Here, you're calling the callback in the success handler of the AJAX call and so now you have access to the data that was returned by the AJAX call.
Have your function return the result of calling jQuery.ajax() - this object implements the jQuery deferred promise interface. That is, an object that promises to return a result some time later.
function updateUser(user_id) {
return jQuery.ajax({...});
}
and then use .done() to register the function to be called when the promise gets resolved:
updateUser(data[i]).done(function(result) {
alert(result);
});
The important part is that deferred objects allow you to complete decouple the initiation of the asynchronous task (i.e. your updateUser function) with what's supposed to happen when that task completes (or fails).
Hence there's no need to pass any callback functions to .ajax, and you can also chain your call with other deferred objects (e.g. animations, other AJAX requests).
Furthermore, you can register as many .done() callbacks as you like, and .fail() callbacks too, without ever having to change updateUser().
The A in ajax is Asynchronous, which means that when the file loaded, the function that started it is done running. Try using jQuery Deferred: http://api.jquery.com/category/deferred-object/
Example:
jQuery("#button").click(function()
{
for(var i = 0;i < data.length; i++)
{
updateUser(data[i]).done(function(result) {
alert(result); //prints 'undefined'
});
}
});
function updateUser(user_id)
{
return jQuery.ajax({
url:"/users/update/"+user_id,
type:"GET",
async: false,
success: (function(data){
...
})
});
}
The function that called the success function is the Ajax request and not the UpdateUser function. So obviously when you return it it will return back from the success callback but not to the UpdateUser function..
Also since the ajax is Asynchronous , buy the time the callback is executed it will come out of the UpdateUser function.. !
pretty sure what is happening (not an expert) but you are returning 'data' for your annonomys function in success and not your whole updateUser function
function updateUser(user_id)
{
var retData;
jQuery.ajax({
url:"/users/update/"+user_id,
type:"GET",
async: false,
success: (function(data){
//if I alert "data" here it shows up correctly
//but if i try to return it like below
//it does not get passed correctly
retData = data;
})
return retData;
});
But like i said, i am no expert.

Categories