0

I am using Node.js. I created a funtion called locationToAddress, but it always returns undefined. This is the code simplified:

var lat = '-34.491093';
var long = '-58.558597';

console.log(locationToAddress(lat, long));

function locationToAddress(lat, long) {
  var preUrl = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=';
  var apiKey = '<API_KEY>';

  var url = preUrl + lat + ',' + long + apiKey;

  var addressString = '';

  request(url, function (error, response, body) {
      try {
          var jsonLocationObject = JSON.parse(body);
          addressString = JSON.stringify(jsonLocationObject.results[0].formatted_address);
          addressString = addressString.replace(/["]/g, '');
          console.log(addressString);
          return addressString;
        } catch (e) {
          return 'Could not find address';
        }
  });
 }

In the console, This code should be seen as:

<FORMATTED_ADDRESS>
<FORMATTED_ADDRESS>

But I see:

undefined
<FORMATTED_ADDRESS>

I know the error is in the return of the value as it works perfectly if I call the function without logging the return.

Iñaki Arango
  • 89
  • 2
  • 8
  • As you can see by the order of the output, the function returns *before* the response was received. `request` is asynchronous. *Returning* a value is always synchronous. – Felix Kling Jan 19 '17 at 21:35

1 Answers1

0

It's because locationToAddress doesn't return anything. The return addressString; and return 'Could not find address'; aren't "part" of locationToAddress.

Because the request in the locationToAddress is asynchronous I bet you wanted to use the function with a different signature:

function locationToAddress(lat, long, callback) { // see the param 'callback'

Then in the request(url, function (error, response, body) { you will not use return but instead callback(null, addressString) and callback('Could not find address'). The 1st argument in the callback is always error and succinct ones are the data you would like to return.

Beware that in NodeJS most of the code is asynchronous and you have to handle it as such. To kind of make your code look synchronous have a look at async.js. The function I use all the times are series, waterfall and autoInject.

* Complete rewrite with a callback *

function locationToAddress(lat, long, callback) {  // <--- CHANGE
  var preUrl = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=';
  var apiKey = '<API_KEY>';

  var url = preUrl + lat + ',' + long + apiKey;

  var addressString = '';

  request(url, function (error, response, body) {
      try {
          var jsonLocationObject = JSON.parse(body);
          addressString = JSON.stringify(jsonLocationObject.results[0].formatted_address);
          addressString = addressString.replace(/["]/g, '');
          console.log(addressString);
          return callback(null, addressString); // CHANGE - null represents "no error"
        } catch (e) {
          return callback('Could not find address'); // CHANGE - nonnull 1st param means an error occured
        }
  });
 }
Amio.io
  • 20,677
  • 15
  • 82
  • 117
  • It does, the line "return addressString" does that. – Iñaki Arango Jan 19 '17 at 21:35
  • @PaulBentley — That line is not part of the `locationToAddress` function. – Quentin Jan 19 '17 at 21:35
  • @PaulBentley: That line is inside the function you pass to `request`, not in `locationToAddress`. `return` statements don't cross function boundaries. Here is a simplified example: `function foo() { function bar() { return 42; }; bar(); return 21; };` What do you think `foo` returns? – Felix Kling Jan 19 '17 at 21:35
  • How would I call the function using callback instead of return and how do I retrieve the result? – Iñaki Arango Jan 19 '17 at 22:06
  • @PaulBentley, I have added the code with the callback. – Amio.io Jan 20 '17 at 07:48