Passing data with "return"

  • Thread starter SteveYoungTbird
  • Start date
S

SteveYoungTbird

I am calling the function autoPost() with:

heights = autoPost(hundredMeters);
alert(heights)

function autoPost(points) {
var req, reply,
data = "latlng=" + points ;
if(window.XMLHttpRequest) req = new XMLHttpRequest();
else if (window.ActiveXObject) req = new
ActiveXObject(Microsoft.XMLHTTP);
req.onreadystatechange = function(){
if(req.readyState == 4){
if(req.status == 200){
reply = req.responseText;
alert(reply);
return reply;
}
else {
alert("Error: returned status code " + req.status + " "
+ req.statusText);
}
}
};
req.open("POST", "some.php", true);
req.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
req.send(data);
};

The alert(reply) in the function autoPost shows the correct data but the
alert(heights) in the calling function shows "undefined". Using:

reply = eval(req.responseText);

gives an evaluated array for alert(reply) but still "undefined" for
alert(heights).

How can I pass the returned POST data to another function?
 
T

Thomas 'PointedEars' Lahn

SteveYoungTbird said:
I am calling the function autoPost() with:

heights = autoPost(hundredMeters);
alert(heights)

function autoPost(points) {
var req, reply,
data = "latlng=" + points ;
if(window.XMLHttpRequest) req = new XMLHttpRequest();

This can work, but the feature test is flawed. Change to (e.g.):

var
req = null,
t = typeof XMLHttpRequest;

if (t == "undefined" || (t == "object" && XMLHttpRequest))
{
try
{
req = new XMLHttpRequest();
}
catch (e)
{
req = null;
}
}

See also user-defined isMethod() and isHostMethod() implementations.
else if (window.ActiveXObject) req = new
ActiveXObject(Microsoft.XMLHTTP);

This cannot work; the type-converting test is error-prone and the argument
needs to be a string value. Change to (e.g.):

if (!req)
{
if (typeof ActiveXObject != "undefined")
{
try
{
req = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
req = null;
}
}

See also the user-defined jsx.tryThis().

Should you want to access the filesystems with XHR, you should try
ActiveXObject() first, because XMLHttpRequest() does not support `file:'
URIs in MSHTML.
req.onreadystatechange = function(){
if(req.readyState == 4){
if(req.status == 200){
reply = req.responseText;
alert(reply);
return reply;
}
else {
alert("Error: returned status code " + req.status + " "
+ req.statusText);

Remove those alerts() or change them into feature-tested console.log() for
production code.
}
}
};
req.open("POST", "some.php", true);
req.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");

You can lose that call, at least you should feature-test it.
req.send(data);

Given the request header, should you not be calling encodeURIComponent()
somewhere before? Do not rely on implementation-specific behavior here.
};

The alert(reply) in the function autoPost shows the correct data but the
alert(heights) in the calling function shows "undefined".

Of course. autoPost() does _not_ return a value (explicitly), the event
listener referred to by `req.onreadystatechange' does (to somewhere you
have no access to; it really should not return a value [explicitly]).
Using:

reply = eval(req.responseText);

gives an evaluated array for alert(reply) but still "undefined" for
alert(heights).

Same problem.
How can I pass the returned POST data to another function?

Pass the object reference to the function that makes the request
(or builds the event listener), then call the referenced function.
See closures.


PointedEars
 
S

Scott Sauyet

[ using AJAX call...]
How can I pass the returned POST data to another function?

The problem is that the XMLHttpRequest call is asynchronous. Your
function is returning before the XHR call is complete.

One solution would be to pass a callback function to be run on
successful data retrieval, something like this:

function autoPost(points, callback) {
// ....
if(req.status == 200){
reply = req.responseText;
callback(reply);
// ...
}

autoPost(hundredMeters, function(results) {
heights = results;
alert(heights) ;
});

Good luck,

-- Scott
 
S

SteveYoungTbird

Scott said:
[ using AJAX call...]
How can I pass the returned POST data to another function?

The problem is that the XMLHttpRequest call is asynchronous. Your
function is returning before the XHR call is complete.

One solution would be to pass a callback function to be run on
successful data retrieval, something like this:

function autoPost(points, callback) {
// ....
if(req.status == 200){
reply = req.responseText;
callback(reply);
// ...
}

autoPost(hundredMeters, function(results) {
heights = results;
alert(heights) ;
});

Good luck,

-- Scott

That makes sense, many thanks.

Regards, Steve.
 
S

Scott Sauyet

[ using AJAX call...]
How can I pass the returned POST data to another function?
The problem is that the XMLHttpRequest call is asynchronous.  Your
function is returning before the XHR call is complete.
One solution would be to pass a callback function to be run on
successful data retrieval [ ... ]
1) Doesn't the statement "if(req.readyState == 4)" mean that the
XMLHttpRequest has been completed? After all the "alert(reply)" in
this conditional statement works but the "return" directly after it
doesn't

It's an easy mistake to make. Let me see if I can break it down
better:

You have an AJAX handler function which is anonymous, but let's name
it explicitly:

function ajaxHandler(){
if(req.readyState == 4){
if(req.status == 200){
var reply = req.responseText;
alert(reply);
return reply;
}
else {
alert("Error:...");
}
}
};

Then you use it like this (oversimplified):

function autoPost(points) {
var req, data = "latlng=" + points;
req = new XMLHttpRequest();
req.onreadystatechange = ajaxHandler;
req.open("POST", "some.php", true);
req.setRequestHeader("Content-Type", "...");
req.send(data);
};

Notice that the function autoPost does not have a "return" statement.
But even if it did, there is no data ready to return by the time the
function completes. Events take this order:

1. In some context, autoPost(points) is called.
2. The XHR object is created and the handler (anonymous or not) is
attached to it.
3. The "send" method of the XHR object is called.
4. autoPost returns, returning nothing to your outer context.
5. A request to the server is made.
6. Multiple requests to your handler are made as the readystate
changes.
7, When the readystate reaches 4, if the HTTP status is 200, your
alert is called, and the handler returns a value, but there is nothing
waiting for the return, so the value is discarded.

There really is no way around this (except for synchronous requests,
which are a bad idea in general.)

But if you have a function that handles the data when it's is
available, you can just call it from your AJAX handler:

function handleHeights(heights) {
alert(heights);
}

function ajaxHandler(){
if(req.readyState == 4){
if(req.status == 200){
handleHeights(req.responseText);
}
else {
alert("Error:...");
}
}

This also means you don't need an explicit callback function passed
in, which would be slightly more complicated to handle if your ajax
handler is not inlined like your original; that's probably worth it
only if you're calling autoPost in multiple places. If you are doing
so, we can help you get that right with a closure.
2) If I were to make the call synchronous would that be a "bad thing"
in any way? My script isn't doing anything until the new data arrives.

Stefan is right. It's almost never a good idea to make the UI hang
waiting for a server response. This can mean some real reshuffling of
the code, but that's the price we pay for the advantages of AJAX.

-- Scott
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,930
Messages
2,570,072
Members
46,522
Latest member
Mad-Ram

Latest Threads

Top