0

I'm developing a Javascript app. It's my first attempt at a somewhat more complex application and I'm running into issues with Promises.

<!DOCTYPE html>
<html>
  <head>
    <title>Images</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      ...
    </style>
    <script src="http://js.pusher.com/2.2/pusher.min.js"></script>
    <script async defer
       src="https://maps.googleapis.com/maps/api/js?key=key&callback=initMap">
    </script>
  </head>
  <body>
    <div id="map"></div>

    <script>
      var map;

      //setup Pusher API
      var channel = "channel";
      var pusher = new Pusher(appid);
      var title;
      var Channel = pusher.subscribe(channel);

      function getTitle() {
        return new Promise(function(resolve, reject) {
            Channel.bind("new-listing", function(listing) {
              title = listing['title'];    
              resolve(title);
            }, 0);
          });
        }

      getTitle().then(function(title) {
        return title;
      });
      // console.log("Title: " + title);

      function findCoordinates() {
          return new Promise(function(resolve, reject) {
            geocoder.geocode( { 'address': address}, function(results, status) {
               latitude = results[0].geometry.location.lat();
               longitude = results[0].geometry.location.lng();

             resolve(latitude, longitude);
            }, 0);
          });

        }

       findCoordinates().then(function(latitude, longitude) {
         console.log("Latitude: " + latitude);
         console.log("Longitude: " + longitude);
      });
      // console.log("Latitude: " + latitude);

      function initMap() {
        var postion = {lat: latitude, lng: longitude}; //here I need latitude and longitude
        var map = new google.maps.Map(document.getElementById('map'), {
          zoom: 3,
          center: postion
        });

        var marker = new google.maps.Marker({
          position: postion,
          map: map,
          title: title //here I need title
        });

        marker.addListener('click', function() {
          infowindow.open(map, marker);
        });

      }
    </script>

  </body>

</html>   

I have three issues:

  1. While the promises are working, the problem is that the title is still not available outside that promise
  2. Same with latitude + I need to have both latitude and longitude available
  3. Another issue is that my code now complains that geocoder is not defined inside the promise.

Any feedback really appreciated.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
wiwa1978
  • 2,317
  • 3
  • 31
  • 67
  • The scope of `title` is the expected one (as opposed to `latitude` and `longitude`), but your actual problem is the asynchrony of the callbacks. – Bergi Aug 31 '16 at 19:13
  • I read the answer of the similar question, and adapted my question to be more specific. Have to admit that even after reading the answer, I don't see it. – wiwa1978 Aug 31 '16 at 19:52
  • `setTimeout` is like `Channel.bind`, and `'Test message'` is like `listing['title']`. With a promise for that, and a promise for the coordinates, you can use `Promise.all` and then call your `initMap` once all data has arrived. – Bergi Aug 31 '16 at 20:51
  • @Bergi Thanks, slowly getting there based on your feedback. I have rewritten the original question but run into some issues still. – wiwa1978 Aug 31 '16 at 21:19
  • Can you show us where you are calling `initMap`? It should wait for the promises, and take the resolution values as paramters. And regarding `longitude`, just put that in an object together with the `latitude` so that you can resolve with both. – Bergi Aug 31 '16 at 21:52
  • @Bergi I have added the full (current) code of my HTML file for completeness. – wiwa1978 Aug 31 '16 at 22:00

1 Answers1

0

The problem is that the title is still not available outside that promise

It will never be. That might allow you to access it before it has been initialised, so you won't have a global variable for the title - you have a global promise for it.
You can access the title by calling then on the promise, which possibly will needt to wait for the value to arrive.

Same with latitude + I need to have both latitude and longitude available

Same here. Notice that you cannot call resolve with two arguments, you have to pass an object instead.

Another issue is that my code now complains that geocoder is not defined inside the promise.

Unlikely that has changed. Maybe you need to wait with calling findCoordinates until the geocoder script has loaded.

Most of your code looks good already, now you just have to store the promises in variables, and wait for them in the initMap function:

function getTitle(channel) {
  return new Promise(function(resolve, reject) {
    channel.bind("new-listing", resolve);
  }).then(function(listing) {
    return listing['title'];
  });
}

function findCoordinates(address) {
  return new Promise(function(resolve, reject) {
    geocoder.geocode( { 'address': address}, function(results, status) {
      // if (status not ok) return reject(status);
      resolve(results);
    }, 0);
  }).then(function(results) {
    var latitude = results[0].geometry.location.lat();
    var longitude = results[0].geometry.location.lng();
    console.log("Latitude: " + latitude);
    console.log("Longitude: " + longitude);
    return {lat: latitude, lng: longitude});
  });
}

//setup Pusher API
var pusher = new Pusher(appid);
var channel = pusher.subscribe("channel");

var titlePromise = getTitle(channel);
var coordinatesPromise = findCoordinates(…); // dunno where you got the address from

// called by the google maps script when ready
function initMap() {
  Promise.all([titlePromise, coordinatesPromise]).then(function(res) {
    var title = res[0];
    var position = res[1];

    var map = new google.maps.Map(document.getElementById('map'), {
      zoom: 3,
      center: position
    });
    var marker = new google.maps.Marker({
      position: position,
      map: map,
      title: title
    });

    marker.addListener('click', function() {
      infowindow.open(map, marker);
    });
  });
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375