Modify global javascript variable inside a function - javascript

I'm trying clone a json object inside a function wanting to access the object outside the function. But when function is done, the object still seems to be undefined. Seems like it's not the same variable?
var jsonUserObj;
$.getJSON("user.json", function(content){
jsonUserObj = $.parseJSON(JSON.stringify(content));
console.log(content);
console.log(jsonUserObj); //looks fine!
});
console.log(jsonUserObj); //undefined
inside the callback function it contains all the data, but it does not remain outside of it. How to make it assessible globally?

$.getJSON is asynchronous so console.log at the end of your code runs before $.getJSON returns its result.
You should modify the variable inside the callback (where it looks fine) and then use the variable inside that function, this callback is the only place where you can guarantee your variable is set.
You could also use the synchronous version of $.ajax but that's really not recommended (and probably unnecessary).

You got a typo:
console.log(jsonUserObject);
It should be
console.log(jsonUserObj);

You need to declare var jsonUserObj outside a function.
Also it looks like you have a typeo, is it jsonUserObj or jsonUserObject?

Could it be a question of timing? If that getJSON method is firing asynchronously then it may not have returned it's value by the time you have fired the last line. Does that make sense?

$.getJSON performs an ajax call, which is asynchronous. The code after it will continue evaluating while it waits for a response. When the response comes back, the program flow will jump back into the success/error/complete handlers of the ajax call.
tldr: Anything you do with data from an ajax call must be in the success handler of that ajax call.

Related

javascript - Order of executing functions

I have some javascript functions being called on Document Ready:
fogFields();
getLoS();
getShips();
startGame();
getNextMove();
However, it is as though getNextMove() is being called first, most likely as all it does is an ajax call and alerts the result. All the other functions have more work, so, the first thing that happens on load is the getNextMove() alert, and in the background you can see that none of the other functions did their work. Until I click OK on the alert window, no results are shown. Can I make it so that until a function finishes, the next wont even start. Some functions call their own extra functions before they finish, and that works in order, but I cant do that with the whole code...
Given the code in your question, there is no way the call to getNextMove can be invoked before startGame has been exited, regardless of their contents.
It may be true that a function that has been scheduled asynchronously (via timeout, AJAX callback etc.) within startGame completes at any time before or after the invocation of getNextMove, but this is a separate issue. To resolve that issue we need to know more about the contents of the functions.
If the other functions have an AJAX call in them, then these AJAX calls most certainly take a callback argument, which is a function that gets executes, when the AJAX call has finshed. Now, if you want to execute your functions in a way, the one function starts when the AJAX call of the previous function finished, you can add an additional callback argument to your own functions, which will then be passed to the AJAX calls. This should illustrate what I mean:
function logFields(callback) {
ajaxCall(callback);
}
function getLoS(callback) {
ajaxCall(callback);
}
function getShips(callback) {
ajaxCall(callback);
}
function startGame(callback) {
ajaxCall(callback);
}
function getNextMove() {
}
fogFields(function(){
getLoS(function(){
getShips(function(){
startGame(function(){
getNextMove();
});
});
});
});
If all of your functions use a ajax call then just use promises.
Simply return it, for example:
function fogFields(){
return $.ajax();
};
and then just use .then:
fogFields().then(getLos());
more information about deffered object on jquery doc page if you use it.
Or implementation in pure javascript you can find here and more theory here.
or another option, which I will not recommend you is to set async param in $.ajax call to false. Again it's for case you use jQuery.

setting a property on a model in an ajax callback

I'm trying to set a property on a model in an ajax callback that I can use later, and I'm not sure if I can do this.
var self = this;
$.ajax {
self.views.someProperty = // something i get back from the server
}
then later do something with this.views.someProperty. Currently I get this.views.someProperty is undefined. I was wondering if I'm going about this correctly or not.
First off, you code snippet doesn't really make sense. $.ajax() calls a callback function when it's done with the result it retrieved and your code snippet doesn't show that proper form.
Assuming you are properly specifying a callback function, here are some other possible issues:
Timing - the result of the ajax call will not be available until AFTER the completion callback is called. This is some time later after $.ajax() is called. The result will not be available in code that executes right after $.ajax().
Does self.views exist already? If not, then setting self.views.someProperty would cause an error and would not work.
When you access this.views.someProperty later, you obviously need to make sure that this is the right value.
You can check the first item by putting a console.log("ajax call finished") in your ajax completion callback and a console.log("accessing someProperty") right before you try to access the value and then verify that the ajax completion is called before you try to access it.
You can check items 2 and 3 by examining the data in the debugger to make sure everything is what you intend.

Possible Javascript scope issue

I'm sort of a noob with this so please forgive me :)
I can't get this one part of the function to update the variable. Could anyone possibly take a look a see what I'm doing wrong?
http://pastie.org/private/zfnv8v2astglabluo89ta
From line 142 thru 172 I'm not getting any results in the end. I've tested inside that function to make sure it is actually returning data, but the "body" variable is passing back up after line 172. So if I look at my generated HTML on the page, it simply looks the function skips from 140 to 174.
Thanks for any feedback!!
Your $.get is asynchronous. That means it will finish sometime AFTER the rest of the code, thus you won't see it's effect on the body variable inside that function. Instead, it's success callback function will be called long after this function has already finished.
To chain multiple asynchronous ajax calls like you have here, you can't just use normal sequential programming because asynchronous ajax calls aren't sequential. The network request is sent, then your javascript continues executing and SOMETIME LATER when the response arrives, the success handler is called and is executed.
To run sequential ajax calls like you have, you have to nest the work inside the success handler so that the ONLY code that uses the response is actually in the success handler. In pseudo-code, it looks like this:
$.get(..., function(data) {
// operate on the results only in here
// a second ajax function that uses the data from the first
// or adds onto the data from the first
$.get(..., function(data) {
// now finally, you have all the data
// so you can continue on with your logic here
});
// DO NOT PUT ANYTHING HERE that uses the responses from the ajax calls
// because that data will not yet be available here
});
You cannot do what you're doing which is like this:
var myVariable;
$.get(..., function(data) {
// add something to myVariable
});
$.get(..., function(data) {
// add something to myVariable
});
$.get(..., function(data) {
// add something to myVariable
});
// do something with myVariable
None of those ajax calls will have completed before the end of your function. You have to follow a design pattern like in my first example.
For more advanced tools, one can always use jQuery deferreds which are just a different way of defining code to run after an ajax call is done. It looks a little more like sequential programming even though it's really just scheduling code to run the same way my first code example does.
Function 8 will be invoke after line 174-180. You must put code from 174-180 line to the end of function

Ajax event handler does not update variables?

I'm having issues getting a variable declared in an .click function to be updated in a Get function within the click function. I've gathered that even though the variable has the same name, within the Get function it is really declaring it anew.
I've tried to find examples helping me, but it appears to me that the Get method is such a specialized function that the examples didn't seem to apply.
I would like the value of 'SettingContentToEdit' to get updated with information retrieved with the Get function.
Below is the code.
Thank you for your help!
$(".cellSetting").click(function () {
var clickedClass = $(this).attr("class");
var clickedItemID = $(this).attr("id")
var SettingContentToEdit = "not changed";
var JSONSend = {
'ItemName': clickedItemID, //send the item name so the model knows which one to pull up!
'ItemSetting': clickedClass
};
$.get(
'/Home/getItem',
JSONSend,
function (data) {
// $('#dialog').html(data.ItemSettings[data.SettingToEdit]);
SettingContentToEdit = data.ItemSettings[data.SettingToEdit];
alert(SettingContentToEdit); //returns the correct info
}
);
alert(SettingContentToEdit); //returns "not changed"
});
Your issue is that your ajax call is asyncronous. The success handler for the get() function is called some time after your click handler and the alert() has already completed. You can refer to the local variables in your success handler, but the code that follows the success handler executes BEFORE the success handler does.
This is because your get() operate is asynchronous. Calling it just STARTS the networking operation and then your javascript execution continues (while the networking operation works in the background). After starting the networking operation, your alert() is called. Then, some time LATER, the Ajax call completes and the success handler is executed.
This is a very common mistake and has indeed been asked and answered hundreds (if not thousands) of times here on SO (I've personally probably answered 20-30) so you are not alone in missing this understanding at first.
If you want to use the results of the ajax operation, then you need to put the code that does that either in your success handler or put it in a function that you call from your success handler. You cannot put it after the get() function because it will execute too soon before the results are known.
AJAX is asynchronous. If you check SettingContentToEdit a second or so later than you are doing, you'd see the value has updated.
Either put your code inside the get function (where you have your alert showing the correct value) or make the request synchronous (you'll have to look up the jQuery docs because I don't use jQuery).

array.push does not work in FF, but works in Chrome... any ideas?

This only works in Chrome, not FF:
var menu = new Array();
$.couch.db("foo").allDocs({
success: function(d) {
for(var i=0;i<=d.total_rows-1;i++){
menu.push(d.rows[i].id);
};
}
});
console.log(menu);
I can console.log "menu" inside the function, but not outside. It's like it looses its scope. Any ideas?
Your success function gets called later, once you've received a response from $.couch.db, so when you reach console.log(menu); you still get the initial value.
Try declaring var menu = []; instead of new Array() - it shouldn't make any difference, but you never know.
Also, try putting console.log(menu); inside the loop, and see... oh, wait.
Forget the above, I just re-read the code.
I'm pretty sure allDocs() is an asynchronous function. You're trying to access the result after you started the function, but before it completed. All code that relies on menu MUST be in the success function.
Could it be that your function works asynchronous so, that when you console.log(menu) outside of the function it shows original state of the menu.
For example, in jQuery when you're using ajax function you can set parameter "async" to false so that response would be assigned to variable correctly.
The problem is that you are pushing data to the menu array inside a callback. What this means is that your code executes somehow like this:
new array is created
$.couch.db() is called which does something (some asynchronous task, which causes the execution flow to continue)
console.log() is called which usually prints a empty array since menu is empty
$.couch.db() finished doing it's business and has called your "success" callback which fills your array
But, there can be cases where your callback is executed before reaching the console.log() ... so really you are dealing with a race condition here.

Categories

Resources