views:

49

answers:

4

Ok. I'm totally baffled. Here's the code:

$(document).ready(function(){
var newToken = 1;

$.get("junk.php",
    function(newToken) {
        alert(newToken); // alerts "junk"
    });
alert(newToken); // alerts "1"
});

As per my comments, the first alert of newToken is "junk" (the only output of junk.php). Once outside the .get, newToken reverts to "1". I need to get this variable set to the output from junk.php. Is this not possible? I've tried everything, and searched everywhere.

Thanks.

+1  A: 
$(document).ready(function(){
    var newToken = 1;

    $.get("junk.php",
        function(data) {
            alert(newToken); 
        });
    alert(newToken); // alerts "1"
});
Jud Stephenson
In case you didn't see it, Mark, the idea here is that you can reference broader scope variables from within anonymous functions even after the function has stopped running. Basically, the anonymous function that runs on domready becomes a closure when you declare another anonymous function inside it. This means that, even though that domready function has stopped running by the time you .get() comes back, the interpreter still has access to objects created inside it. As you probably just realized, this is one of the most powerful features of Javascript.
treeface
Don't understand this code change. From what I can tell, newToken goes from being local inside the .get request, to being undefined. That wouldn't help.
Mark
@Mark - the change is that the argument name in the function was changed from `newToken` to `data`. - For an explanation see my answer - @Jud - You should be using `var newToken = 1;`... Why pollute the global namespace?
Peter Ajtai
@Peter, fixed. Not sure why i deleted it in the first place.
Jud Stephenson
should that be alert(data) inside the .get? I don't see why newtoken would have been set to junk there...
Chris
Data is the returned HTML from the Ajax request.
Jud Stephenson
Ah, sorry, I took out that comment that was in the original code.
Jud Stephenson
Ok, this works for bringing the value of newToken IN. But that's not the issue. The problem is getting the value of -now- data into newToken and out of the .get. If I assign newToken = data, the second alert is still the original value of newToken, not what was assigned inside this function.
Mark
A: 

First, your definition of newToken is inside the context of that anonymous function passed to $(document).ready(), so it's not global at all. I don't think this is the problem real, though...

More serious is this: The call to $.get is asynchronous, so control passes immediately to your alert(newToken) statement without waiting for the http request to finish, or for its callback to run. So any code relying on data retrieved in that call should run in its callback.

grossvogel
Sorry, I should have said that I also tried declaring the variable inside and outside of the document-ready function. That was important, and I omitted that. However, it had no impact on the problem.
Mark
@Mark - Variables declared in an outer scope can be accessed from an inner scope (but not vice versa). `var x = 1; $(function() { alert(x); });` will work.
Peter Ajtai
@gross - Which `alert(newToken)` do you mean? There are 2 in the OP. The one that is later in the code gets triggered immediately. The one in the get callback gets triggered second ( **and not immediately** ). But the problem is the name of the argument in the function call back. -- see my answer
Peter Ajtai
A: 

I found the answer - of all places on the jQuery website (surprise, surprise), buried in the commentary.

newToken = $.ajax({ type: "GET", url: "junk.php", async: false }).responseText;

This solves the problem - being that it was asynchronous, and that needed to be set to false. This cannot be accomplished using the jQuery.get(), but must be jquery.ajax, where the async:false can be set.

With the request in this format, newToken can be used throughout the script. Hope this ends up helping someone else.

Mark
This is not the problem. You set the variable name of the returned data to `newToken`, this shadows (covers up) the `newToken` you set equal to 1. --- see my answer.
Peter Ajtai
There were two problems. He was shadowing the variable with an inner variable true. But also, the alert was happening first because of the asynchronous nature of .get().
DGM
@Peter This isn't the problem? It WORKS. The application I was working on works now. With this code. That's what I meant when I said it solves the problem.
Mark
@DGM - Yes, I cover this in my answer, even including an example demonstrating it. - It's unclear to say that `the aler happens first` since there are 2 alerts. The one outside the `.get()` callback happens first. The one in the `.get()` callback happens second.
Peter Ajtai
@Mark - Yes it works, but you're using AJAX synchronously which defeats the purpose essentially.
Peter Ajtai
The purpose is to get the data into the variable. And it works. How does that defeat the purpose???
Mark
+1  A: 

You're shadowing the first newToken variable with a new newToken variable that is used as an argument:

Problem:

$(document).ready(function(){
var newToken = 1; // <== newToken number 1

$.get("junk.php",
    function(newToken) { // <== This is newToken number 2.
                         //     since it's the first argument
                         //     in the get success function it will
                         //     be the data returned.

        alert(newToken); // <== Alerts the data returned. newToken number 1 is 
                         // shadowed, obscured, covered up...
    });
alert(newToken);
});


Work around... use different names, or even the arguments array:

Solution:

$(document).ready(function(){
var newToken = 1;

$.get("junk.php",
    function() {  // <== don't shade newToken
                  //     you could use another variable name like "data"
                  //     but I decided to use the arguments array for kicks

        alert("Data is: " + arguments[0] + // <== junk
              "\nNew Token is: " + newToken); // <== 1
    });
alert(newToken); // alerts "1"
});

Info on $.get()

Note that if you update newToken in the get callback things can get tricky due to the asynchronous nature of the call. Basically, be aware of the fact that everything you write in the callback of $.get() will get executed only when the request is done ( a while later ), but everything after $.get() but within the doc ready will get executed right away, and the get callback will have access to the state of variables as they were when the doc ready function returned................ basically, you can give newToken an initial value and then work with it in the get callback, but anything else might cause results that you don't except.

Some examples:

$(document).ready(function(){
    var newToken = 1;

    $.get("junk.php",
        function() {
            newToken++;
            alert(newToken); // alerts 2, so far so good.
        });
    });

$(document).ready(function(){
    var newToken = 1;

    $.get("junk.php",
        function() {
            newToken++;
            alert("get: " + newToken); // alerts 3 - this is the last alert
        });

    newToken++;
    alert("ready:" + newToken); // alerts 2 - 
                                // this happens before the server responds
});

jsFiddle example

Peter Ajtai
I see this. That's a very interesting thing, especially as my laptop is both client and server, and there is no delay in connecting across the internet. Commenting out the linear-second alert shows that the linear-first alert does indeed trigger second, and alerts '3'. Is this saying, then, that the value is changing, but not fast enough to be used by the program elsewhere?
Mark