0

I am trying to get the user location by using HTML5 geolocation. The lat and lng value are received successfully and I can show it on the map. I want to save the user location to use it later so I defined origin variable and I concatenated the lat and lng variables and then I assigned the concatenated value to origin. When I am trying to use the origin value later its value is undifined. Could someone please tell me when the problem is in the code. I guess the problem is very silly but I cannot solve it. I don't think the problem is related to variable scope.

Here is the code:

let map ;

// initialize the map and show it on the dashboard.
function initMap() 
{
    // Map options.
    let options =
    {
        center :
        {
            lat : 41.015137,
            lng : 28.979530
        },
        zoom : 12
    }

    // New map.
    map  = new google.maps.Map
    (
        document.getElementById('map'),
        options
    );
};

$(document).ready
(
    function()
    {
        $("#order_and_show").click
        (
            function()
            {
                // Change the text of the title and the button when get order from the user. 
                $('#order_title').text('Cancel the order right now') ;
                $('#order_and_show').text('Cancel Now') ;

                // Get user location from browser using HTML geolocation.
                let origin ;

                // HTML5 geolocation.
                if (navigator.geolocation) 
                {
                    navigator.geolocation.getCurrentPosition
                    (
                        function(position) 
                        {
                            let pos = 
                            {
                                lat: position.coords.latitude,
                                lng: position.coords.longitude
                            } ;

origin = position.coords.latitude + ',' + position.coords.longitude ;

                            // Add marker.
                            let marker = new google.maps.Marker
                            (
                                {
                                    position : pos,
                                    map : map,
                                }
                            ) ;

                            // Center the map according to user location.
                            map.setCenter(pos);

                            // Add popup window for user location information
                            let infoWindow = new google.maps.InfoWindow
                            (
                                {
                                    content : '<h6>Your Location</h6>'
                                }
                            ) ;

                            marker.addListener
                            (
                                'click', 
                                () =>
                                {
                                    infoWindow.open(map, marker) ;
                                }
                            ) ;
                        }, 
                        function() 
                        {
                            handleLocationError(true, infoWindow, map.getCenter());
                        }
                    );
                } 

                else 
                {
                    // Browser doesn't support Geolocation
                    handleLocationError(false, infoWindow, map.getCenter());
                }

                // Handle Geolocation errors.
                function handleLocationError(browserHasGeolocation, infoWindow, pos) 
                {
                    infoWindow.setPosition(pos);

                    infoWindow.setContent
                    (
                        browserHasGeolocation ? 'Error: The Geolocation service failed.' : 'Error: Your browser does not support geolocation.'
                    ) ;

                    infoWindow.open(map);
                }

                console.log(origin) ;


            }
        ) ;


    }   
) ;
Mohamad
  • 37
  • 9
  • 1
    the problem is the scope of variable, use var instead of let. more [here](https://stackoverflow.com/a/11444416/2996989) – Ahmed Sunny Mar 07 '20 at 17:47
  • Thanks @AhmedSunny the link you referred was so helpful. But I cannot see the wrong in my code. – Mohamad Mar 07 '20 at 18:03
  • try one thing, console out origin right after concatenation, if its undefined there then its concat issue, – Ahmed Sunny Mar 07 '20 at 18:23
  • I tried to console out origin right after concatenation and I got the right value. – Mohamad Mar 07 '20 at 18:26
  • 4
    The problem is that you try to access `origin` outside the callback. When you do that the callback hasn't been executed yet thus `origin` is still `undefined`. Do all work related to `origin` inside the `navigator.geolocation.getCurrentPosition` callback. Set `origin` to a promise that you resolve in the callback. Allowing you to work with promise callbacks/async await methods later on. I suggest taking a look at: [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – 3limin4t0r Mar 07 '20 at 18:33

2 Answers2

1

The problem with your current code is that you try to access origin outside of the callback that sets it. The getCurrentPosition callback is probably executed asynchronously, thus when you try to access origin outside of the callback the callback function is not yet executed resulting in a origin value of undefined. You could use promises or async/await to solve this issue. Such a solution might look like this:

$(document).ready(function () {
  const map = new google.maps.Map(
    document.getElementById("map"),
    { center: { lat: 41.015137, lng: 28.979530 }, zoom: 12 }
  );

  function handleLocationError(infoWindow, msg) {
    infoWindow.setPosition(map.getCenter());
    infoWindow.setContent(msg);
    infoWindow.open(map);
 }

  $("#order_and_show").click(async function () {
    // notice the async keyword ^
    $('#order_title').text('Cancel the order right now');
    $('#order_and_show').text('Cancel Now');

    let position, origin;
    if (navigator.geolocation) {
      try {
        // await the position before continuing
        position = await new Promise((resolve, reject) => {
          navigator.geolocation.getCurrentPosition(resolve, reject);
        });
        let pos = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        };
        origin = position.coords.latitude + ',' + position.coords.longitude;
        let marker = new google.maps.Marker({position: pos, map: map});
        let infoWindow = new google.maps.InfoWindow({
          content: '<h6>Your Location</h6>'
        });

        map.setCenter(position);
        marker.addListener('click', () => infoWindow.open(map, marker));
      } catch (error) {
        // I'm not sure how you are able to access infoWindow here since it's
        // created in the try block after the error is thrown.
         handleLocationError(infoWindow, 'Error: The Geolocation service failed.')
      }
    } else {
      // Same here, you don't have access to infoWindow, since it's not created
      // yet. However both the above and this are present to mimic the question
      // structure.
      handleLocationError(infoWindow, 'Error: Your browser does not support geolocation.');
    }

    // origin should be available unless geolocation isn't supported or
    // getCurrentPosisiton failed to execute successfully
    console.log(origin);
  });
});

For more info about working with asynchronous behaviour I recommend checking out the MDN Using Promises guide.

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
  • You are right I try to access origin outside of the callback that sets it. The same problem has already discussed here:[https://stackoverflow.com/questions/7189492/javascript-assigning-the-return-value-of-a-callback-function-to-global-variable] – Mohamad Mar 12 '20 at 20:52
0

I am not sure but I think problem seems to be with this line:

 let infoWindow = new google.maps.InfoWindow({
   content: "<h6>Your Location</h6>"
 });

You have declared infoWindow using let keyword which is why I think it is scoped within function(position) { .. } block and which is why infoWindow is being passed to handleLocationError function. The same could be said for let pos variable. declaring your variables globally could solve the problem.

declare pos, marker and infoWindow varibles in the same line let origin; like so:

let origin, pos, marker, infoWindow;

Final Code Should look like this, hope it helps:

let map;

// initialize the map and show it on the dashboard.
function initMap() {
  // Map options.
  let options = {
    center: {
      lat: 41.015137,
      lng: 28.97953
    },
    zoom: 12
  };

  // New map.
  map = new google.maps.Map(document.getElementById("map"), options);
}

$(document).ready(function() {
  $("#order_and_show").click(function() {
    // Change the text of the title and the button when get order from the user.
    $("#order_title").text("Cancel the order right now");
    $("#order_and_show").text("Cancel Now");

    // Get user location from browser using HTML geolocation.
    let origin, pos, marker, infoWindow;

    // HTML5 geolocation.
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        function(position) {
          pos = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };

          origin = position.coords.latitude + position.coords.longitude;

          // Add marker.
          marker = new google.maps.Marker({
            position: pos,
            map: map
          });

          // Center the map according to user location.
          map.setCenter(pos);

          // Add popup window for user location information
          infoWindow = new google.maps.InfoWindow({
            content: "<h6>Your Location</h6>"
          });

          marker.addListener("click", () => {
            infoWindow.open(map, marker);
          });
        },
        function() {
          handleLocationError(true, infoWindow, map.getCenter());
        }
      );
    } else {
      // Browser doesn't support Geolocation
      handleLocationError(false, infoWindow, map.getCenter());
    }

    // Handle Geolocation errors.
    function handleLocationError(browserHasGeolocation, infoWindow, pos) {
      infoWindow.setPosition(pos);

      infoWindow.setContent(
        browserHasGeolocation
          ? "Error: The Geolocation service failed."
          : "Error: Your browser does not support geolocation."
      );

      infoWindow.open(map);
    }

    console.log(origin);
  });
});

Sushmit Sagar
  • 1,412
  • 2
  • 13
  • 27
  • there are no problems with pos, marker and infoWindow variables the problem I faced that the value of origin variable is undifined. I tried as you said to declare the origin variable as global variable but that did not solve my problem. – Mohamad Mar 07 '20 at 18:20
  • the code segment you mentioned works fine. there is no problem with it. – Mohamad Mar 07 '20 at 18:23
  • I doubt that `handleLocationError` function will have access to `infoWindow and pos` in future. – Sushmit Sagar Mar 07 '20 at 18:26