JS Weird Question: Object property undefined ... but it's there

any JS experts there that can explain this?

Both getOrigin() and getDestination() from an API returns an object.

If I immediately query the object (orgPoint.geometry.coordinates), I get undefined value.

But if I give it a time delay of 0ms, I get the correct values?

        // returns an Object
        orgPoint = directions.getOrigin();
        destPoint = directions.getDestination()

        // why is this not working?
        console.log('...... no time delay .......');
        console.log('Origin: ', orgPoint.geometry.coordinates);         // returns undefined in Console
        console.log('Destination: ', destPoint.geometry.coordinates);   // returns undefined in Console

        // but give it a time delay of 0ms, it works
        console.log('...... now using setTimeout() .......');
        setTimeout(function(){
            console.log('Origin(t): ', orgPoint.geometry.coordinates);     // returns correct value
            console.log('Destination(t): ', destPoint.geometry.coordinates);  // returns correct value
        }, 0);

Result:

...... no time delay .......
Origin:  undefined
Destination:  undefined

...... now using setTimeout() .......
Origin(t):  [-87.0353, 35.6151]
Destination(t): [-86.7744, 36.1622]

It may be async. That was my first thought… but if I go to the browser console, and type the variables orgPoint and destPoint, the whole object tree is right there. I can see the values.

If I type in the browser, orgPoint.geometry.coordinates, I get the correct answer.

So one would assume, okay it works. Now I can use it in my JS code.
But assigning via JS code myvalue = orgPoint.geometry.coordinates (the same code I used in console)
produces undefined.

The only way for JS code to work is wrapping it in a timeout() function.

Here’s the relevant Github source

the getOrigin() and getDesination() methods don’t have callbacks.

In the source code, it’s a simple return statement.

getOrigin: function () {
        return this.origin;
},

getDestination: function () {
        return this.destination;
},

I dont have this demo code on github, but here’s the complete code. It’s only short.

UPDATE: Okay, after playing with this some more, I do think I need a time delay (1 second is good enough) to allow the getOrigin and getDestination sufficient time to do their geocoding. Otherwise, the getDestination() part may have undefined values.

This demo code works, I’m okay with this now. Now, I can properly integrate this with my project.

Thanks for looking into this, and here’s the working code if you want to play with it.
Just replace with your own access token/api-key.

PS: It’s sprinkled with lots of comments as I was trying to figure this out and learning it.

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Driving directions</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.js'></script>
<link href='https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.css' rel='stylesheet' />
<style>
  body { margin:0; padding:0; }
  #map { position:absolute; top:0; height:600px; width:100%; }
</style>
</head>
<body>
<style>
#inputs,
#errors,

#inputs {
    z-index: 10;
    top: 410px;
    left: 10px;
    position: relative;
    width: 500px;
    margin: auto;
}

#directions {
    background: rgba(0,0,0,.8);
    top: 620px;
    overflow: auto;
    width: 90%;
    margin: auto;
    position: relative;
    height: 400px;
}

#errors {
    z-index: 8;
    opacity: 0;
    padding: 10px;
    border-radius: 0 0 3px 3px;
    background: rgba(0,0,0,.25);
    top: 90px;
    left: 10px;
}

</style>

<script src='https://api.mapbox.com/mapbox.js/plugins/mapbox-directions.js/v0.4.0/mapbox.directions.js'></script>
<link rel='stylesheet' href='https://api.mapbox.com/mapbox.js/plugins/mapbox-directions.js/v0.4.0/mapbox.directions.css' type='text/css' />

<div id='map'></div>
<div id='inputs'></div>
<div id='errors'></div>
<div id='directions'>
  <div id='routes'></div>
  <div id='instructions'></div>
</div>

<script>
    var startAddress = 'Denver, CO';
    var endAddress = 'St. Louis, WA';
    
    var orgPoint, destPoint;
    L.mapbox.accessToken = 'replace-with-own-api-key';

    var map = L.mapbox.map('map', 'mapbox.streets', {
        zoomControl: true
    }).setView([39, -98.5], 5); // center of USA

    // move the attribution control out of the way
    map.attributionControl.setPosition('bottomright');

    // create the initial directions object, from which the layer
    // and inputs will pull data.
    var directions = L.mapbox.directions({
        profile: 'mapbox.driving',
        units: 'imperial'
    });

    var directionsLayer = L.mapbox.directions.layer(directions)
        .addTo(map);

    //* input form fields for start and ending locations
    //* but this is not required to be shown if we use setOrigin() and setDestination() methods 
    // var directionsInputControl = L.mapbox.directions.inputControl('inputs', directions).addTo(map);

    //* hide error messages
    // var directionsErrorsControl = L.mapbox.directions.errorsControl('errors', directions).addTo(map);

    //* the actual route to get from origin to destination
    var directionsRoutesControl = L.mapbox.directions.routesControl('routes', directions).addTo(map);

    //* textual instructions
    var directionsInstructionsControl = L.mapbox.directions.instructionsControl('instructions', directions).addTo(map);

    map.on('ready', function(){
        // set the origin and destination point.
        directions.setOrigin(startAddress);     // Start point, array[lng, lat] or address, or place name
        directions.setDestination(endAddress);  // End point, array[lng, lat] or address, or place name    

        // check if we have valid origin and destination points
        if (directions.queryable()) {
            // if valid origin and destination points, fire the query
            // this will drop the origin and destination map markers and draw the routes
            directions.query();

            // Q: How do we zoom so origin and destination points are shown automatically?
            // A: we use .fitbounds() 

            // Q: but how do we get lat/lng of our origin and destinations.
            // A: do a getOrigin() and getDestination(), and extract lat/lng object

            // getXXXX() returns an Object
            orgPoint = directions.getOrigin();
            destPoint = directions.getDestination();
            
            setTimeout(function(){
                // so Directions API automatically makes (2) additional Geocoding API call$
                // converting origin and destination from simple string to a lat/lng coordinates
                // map.fitBounds(bounds);
                orgPoint = orgPoint.geometry.coordinates;
                destPoint = destPoint.geometry.coordinates;

                map.fitBounds([
                    [orgPoint[1], orgPoint[0]],     // NOTE COORDINATES!!! It's ass backwards for this method()! 
                    [destPoint[1], destPoint[0]]
                ]);
            }, 1000);  // give it sufficient time delay, otherwise, getting destination lat/lng may fail. 
        }
        
    })

</script>
</body>
</html>