0

I am working with 2 APIs, From 1st I am extracting the latitude and longitude, and then fetching into my 2nd API parameter to get weather JSON data.

In the form part, I have used a simple text input for entering city names, a date picker from which I can select dates for weather information and a button to submit.

What is the problem?

  1. When I try to dynamically fetch query into my 2nd URL, for some reason it doesn't work, but when i try to render the same this.state.lon it correctly renders out the longitude to my page.
  2. Previously, I thought this is happening because my state object is not updating, and I am calling the 2nd API without any value, but it is not the case.
  3. I have even tried to call apicall1() at very last so everything happens first from the 1st then only I can call the 2nd one. But the same problem.
  4. The 2nd API is getting bad request because the query parameter for lon and lat is empty
import React, { Component } from "react";
import DatePicker from "react-date-picker";

class Form extends Component {
  state = {
    inputCity: "",
    lat: "",
    lon: "",
    date: new Date(),
    condition: "",
    minimumTemperature: "",
    maximumTemperature: "",
    calendar: ""
  };

  apicall() {
    let API_KEY_OPEN_WEATHER = "my api";

    let city = this.state.inputCity;

    let corsCurrent = `http://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=${API_KEY_OPEN_WEATHER}&units=metric`;

    fetch(corsCurrent)
      .then(results => {
        return results.json();
      })
      .then(data => {
        console.log(data);
        let lat = data.coord.lat;
        let lon = data.coord.lon;
        let condition = data.weather[0].main;
        let minimumTemperature = data.main.temp_min;
        let maximumTemperature = data.main.temp_max;
        this.setState({
          lat: lat,
          lon: lon,
          condition: condition,
          minimumTemperature: minimumTemperature,
          maximumTemperature: maximumTemperature
        });
      });
  }

  apicall1() {
    let API_KEY_OPEN_WEATHER = "my api";
    let API_KEY_DARKSKY = "my api";

    let city = this.state.inputCity;
    let lat = this.state.lat;
    let lon = this.state.lon;
    let unix = this.state.calendar;

    let corsCurrent = `http://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=${API_KEY_OPEN_WEATHER}&units=metric`;
    let corsHistorical = `https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/${API_KEY_DARKSKY}/${lat},${lon},1579257722?exclude=currently,flags,minutely,hourly`;
    fetch(corsHistorical)
      .then(results1 => {
        return results1.json();
      })
      .then(data1 => console.log(data1));
  }

  onChange = date => {
    this.setState({ date });
    console.log("changed");
  };

  handleSubmit = e => {
    console.log("submit");
    e.preventDefault();

    this.apicall();

    let year = this.state.date.getFullYear();
    let month = this.state.date.getMonth() + 1;
    let date = this.state.date.getDate();

    let calendarr = year + "," + " " + month + "," + " " + date;
    this.setState({
      calendar: calendarr
    });
  };

  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <input
            onChange={e => this.setState({ inputCity: e.target.value })}
            type="text"
            placeholder="Enter City Name"
            required
          />

          <button type="submit">Submit</button>
        </form>

        <DatePicker onChange={this.onChange} value={this.state.date} />

        <p>{this.state.lat}</p>
        <p>{this.state.lon}</p>
        <p>{this.state.condition}</p>
        <p>{this.state.minimumTemperature}</p>
        <p>{this.state.maximumTemperature}</p>
        <p>{new Date(this.state.calendar).getTime()}</p>
      </div>
    );
  }
}

export default Form;
Sina Farhadi
  • 785
  • 4
  • 18
anshul
  • 661
  • 9
  • 27
  • 1
    I would hide your API credentials – Chris Jan 17 '20 at 15:10
  • 1
    Agreed. Best to delete this question and ask again _without_ the key (anybody can see the history of edits). – mbojko Jan 17 '20 at 15:11
  • @mbojko, there are more API credentials below :-) – Chris Jan 17 '20 at 15:11
  • Where are you calling the second api call? Anyway, your problem seems to be related to asyncronous calls. Try using promises or callbacks in your api calls, and remember that [setState is an asyncronous method too](https://stackoverflow.com/questions/42038590/when-to-use-react-setstate-callback), so if you're using the state values just after updating them, you should use the callback from it. – Italo Ayres Jan 17 '20 at 15:20
  • Let me know if you need help with the code. – Italo Ayres Jan 17 '20 at 15:20
  • @ItaloAyres I am using promises everywhere, still i cannot pass the state values to my query – anshul Jan 17 '20 at 15:22
  • I have even tried calling the 2nd function at very end, still the same error – anshul Jan 17 '20 at 15:30

2 Answers2

0

I noticed you're missing the constructor for your component. I also added CORS to your fetches because your API request is going to another domain.

import React, { Component } from "react";
import DatePicker from "react-date-picker";

class Form extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputCity: "",
      lat: "",
      lon: "",
      date: new Date(),
      condition: "",
      minimumTemperature: "",
      maximumTemperature: "",
      calendar: ""
    };
  }

  apicall() {
    let API_KEY_OPEN_WEATHER = "my api";

    let city = this.state.inputCity;

    let corsCurrent = `http://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=${API_KEY_OPEN_WEATHER}&units=metric`;

    fetch(corsCurrent, { mode: "cors" })
      .then(results => {
        return results.json();
      })
      .then(data => {
        console.log(data);
        let lat = data.coord.lat;
        let lon = data.coord.lon;
        let condition = data.weather[0].main;
        let minimumTemperature = data.main.temp_min;
        let maximumTemperature = data.main.temp_max;
        this.setState({
          lat: lat,
          lon: lon,
          condition: condition,
          minimumTemperature: minimumTemperature,
          maximumTemperature: maximumTemperature
        });
      });
  }

  apicall1() {
    let API_KEY_OPEN_WEATHER = "my api";
    let API_KEY_DARKSKY = "my api";

    let city = this.state.inputCity;
    let lat = this.state.lat;
    let lon = this.state.lon;
    let unix = this.state.calendar;

    let corsCurrent = `http://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=${API_KEY_OPEN_WEATHER}&units=metric`;
    let corsHistorical = `https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/${API_KEY_DARKSKY}/${lat},${lon},1579257722?exclude=currently,flags,minutely,hourly`;
    fetch(corsHistorical, { mode: "cors" })
      .then(results1 => {
        return results1.json();
      })
      .then(data1 => console.log(data1));
  }

  onChange = date => {
    this.setState({ date });
    console.log("changed");
  };

  handleSubmit = e => {
    console.log("submit");
    e.preventDefault();

    this.apicall();

    let year = this.state.date.getFullYear();
    let month = this.state.date.getMonth() + 1;
    let date = this.state.date.getDate();

    let calendarr = year + "," + " " + month + "," + " " + date;
    this.setState({
      calendar: calendarr
    });
  };

  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <input
            onChange={e => this.setState({ inputCity: e.target.value })}
            type="text"
            placeholder="Enter City Name"
            required
          />

          <button type="submit">Submit</button>
        </form>

        <DatePicker onChange={this.onChange} value={this.state.date} />

        <p>{this.state.lat}</p>
        <p>{this.state.lon}</p>
        <p>{this.state.condition}</p>
        <p>{this.state.minimumTemperature}</p>
        <p>{this.state.maximumTemperature}</p>
        <p>{new Date(this.state.calendar).getTime()}</p>
      </div>
    );
  }
}

export default Form;
donaldsa18
  • 302
  • 1
  • 4
  • I tied this, still getting the same error, "poor formatted request". I am not able to pass lat and lon to my query – anshul Jan 17 '20 at 15:21
  • I fixed the CORS problem. I can't test the API credentials, but the request went through until reaching data.coord.lat – donaldsa18 Jan 17 '20 at 16:06
0

If you want to call 2nd API call after 1st one, and only in this order, you need asynchronous approach.

You can use async await.

Create async function and inside it use await for 1st call then call the 2nd one.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

flash
  • 32
  • 4