0

it seems I understand the behavior of async/ await, but now-now i am deeply stuck with my problem and cant solve it. I am trying to create weather app and so I need to request the latitude and longitude first, then getting that info to send a request to weather API and get the forecast. As it's said in google documentation

Accessing the Geocoding service is asynchronous since the Google Maps API needs to make a call to an external server.

So I am trying to use async/await to handle it.

import Search from './models/Search';
import * as searchView from './views/searchView';
import { elements } from './views/base';

/*
* Search controller
*/

const state = {

};

const controlSearch = async () => {
  const query = searchView.getInput();

  if (query) {
    state.forecast = new Search(query);

    try {
      await state.forecast.codeAddress();
      await state.forecast.getForecast(state.forecast);
      console.log(state);
    } catch (error) {
      console.log(error);
    }
  }
};

elements.searchForm.addEventListener('submit', (e) => {
  e.preventDefault();
  controlSearch();
});

this is my controller . In the bottom i have put eventListener to form , which the user will use to search the city and then get it's forecast.

This is my Search model

import { key, proxy } from '../config';

export default class Search {
  constructor(query) {
    this.query = query;
  }

  codeAddress() {
    const geocoder = new google.maps.Geocoder();
    geocoder.geocode({ address: this.query }, (results, status) => {
      if (status === 'OK') {
        this.latitude = results[0].geometry.location.lat();
        this.longitude = results[0].geometry.location.lng();
        console.log(this.latitude, this.longitude, 'lat long');
      }
    });
  }

  async getForecast(geometry) {
    console.log(geometry, 'geometry');
    const result = await fetch(`${proxy}https://api.darksky.net/forecast/${key}/${geometry.latitude},${geometry.longitude}`);
    const forecast = await result.json();
    forecast.then((res) => {
      this.forecast = res;
    });
  }
} 

The problem is that when requesting to the darkSky API , the geometry.latitude and geometry longitude are undefined.

How can i handle this problem ?

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Norayr Ghukasyan
  • 1,298
  • 1
  • 14
  • 28

2 Answers2

3

codeAddress doesn't await anything or return something to be awaited. It closes immediately even if the geocode isn't done yet. Have it return a Promise that can be awaited.

codeAddress() {
  return new Promise((resolve, reject) => {
    const geocoder = new google.maps.Geocoder();
    geocoder.geocode({
      address: this.query
    }, (results, status) => {
      if (status === 'OK') {
        this.latitude = results[0].geometry.location.lat();
        this.longitude = results[0].geometry.location.lng();
        console.log(this.latitude, this.longitude, 'lat long');
        resolve();
      } else {
        reject();
      }
    });
  });
}

Unfortunately, you will need to manually return a Promise since the Geocoder.geocode() API only follows a callback style of asynchronization and await will only wait on .then()-ables (like a Promise).

zero298
  • 25,467
  • 10
  • 75
  • 100
0

codeAddress is async (because the response is handled in a callback), but you are not treating it as async. Try this:

async codeAddress() {
  const geocoder = new google.maps.Geocoder();
  return new Promise((resolve, reject) => {
    geocoder.geocode({ address: this.query }, (results, status) => {
      if (status === 'OK') {
        this.latitude = results[0].geometry.location.lat();
        this.longitude = results[0].geometry.location.lng();
        console.log(this.latitude, this.longitude, 'lat long');
        resolve();
      } else {
        reject();
      }
    });
  });
}

There are certainly other ways to convert an function with a callback to an async.

Robert Stiffler
  • 675
  • 3
  • 10