0

I'm very new to React and programming in general so bear with me. I'm working through a tutorial where you fetch data from the Open Weather API and display it. What I don't like is there are two input fields (city) & (country) and I would like to use one input field (city, country) to fetch the data. There might be an API for this on open weather, but I'd like to learn for future situations. After trying a variety of lost attempts and google searches, I've made no progress. Bonus points if you can also error handle and "unhandled error" when text can't be found via the API call (entering a state in the country field)

App.js

import React, {useState} from 'react';
import Form2 from './Form2'
import Weather from './Weather'
import './App.css'


export default function App() {
  const [weather,setWeather] = useState([])
  const APIKEY = 'myKey'

  async function fetchData(e) {
    const city = e.target.elements.city.value
    const country = e.target.elements.country.value
      e.preventDefault()
    const apiData = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city},${country}&APPID=${APIKEY}`)
      .then( res => res.json())
      .then(data => data)
      if(city && country && city !== undefined && country !== undefined) {
      setWeather({
        data: apiData,
        city: apiData.city,
        country: apiData.sys.country,
        description: apiData.weather[0].description,
        temperature: Math.round(apiData.main.temp * 9/5 - 459.67),
        error:""
      }
      )} else {
        setWeather({
          data: '',
          city: '',
          country: '',
          description: '',
          temperature: '',
          error:"Please Type A City And Country"
      }
      )}
  }

  return (
    <div className="App">
      <h3>WEATHER APP</h3>
      <Form2 getWeather={fetchData} />
      <Weather
      city={weather.city}
      country={weather.country}
      description={weather.description}
      temperature={weather.temperature}
      error={weather.error}
      />
      {console.log(weather.data)}
    </div>
  );
}

Form.jsx

import React from 'react'

const Form2 = (props) => {
    return (
        <form onSubmit={props.getWeather}>
            <input
            type='text'
            placeholder='city'
            name='city'
            />
            <input
            type='text'
            placeholder='country'
            name='country'
            />
            <button>Submit</button>
        </form>
    )
}

export default Form2; 

Weather.jsx

import React from 'react'

const Weather = ({description, location, error, temperature}) => {
    return (
        <div>
            {location && <p>{location}</p>}
            {temperature && <p>{temperature} °F</p>}
            {description && <p>Conditions: {description}</p>}
            {error && <p>{error}</p>}
        </div>
    )
}

export default Weather; 

3 Answers 3

1

in your form.jsx, replace your 2 inputs with 1 input and let's call it location

    <input
    type='text'
    placeholder='location'
    name='location'
    />

For more challenge for you I would add some regex to that input so that the input is the name of the city followed by space followed by country

then in your app.js, create const location = e.target.elements.location.value.split(" ") then replace

const city = e.target.elements.city.value

with const city = e.target.elements.location[0].value

and const country = e.target.elements.country.value

with const city = e.target.elements.location[1].value

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I actually tried doing location and combining the city and state but don't have a good grasp on "e.target.elements" and how text fields are handled. I'm going to do some reading on this and use your solution here. I'll figure out the regex to handle the "city, country" on the input.
1

You can assign a value property on the input and also a onChange function to update that value, then u can get the values from the 2 variables.

function App() {
  const [value, setValue] = useState("");
  const handlSubmit = () => {
    if (value) {
      const splitted = value.split(",");
      console.log(`City is ${splitted[0]} and Country is ${splitted[1]}`);
    } else {
      console.log("Input is empty");
    }
  };
  return (
    <div className="App">
      <input
        value={value}
        onChange={e => setValue(e.target.value)}
        type="text"
        placeholder="city"
        name="city"
      />
      <button onClick={handlSubmit}>Submit</button>
    </div>
  );
}

A working example

4 Comments

Thank you for your response but this doesn't solve what I'm trying to do. The example still has 2 text inputs, one each for City and Country, respectively. I would like to use only 1 text input (ex. "Rome, Italy"). This would then have to parse City and Country to the API to fetch the data per the required API properties.
So why don't you do exactly what you said ? Just use one input and parse the city and country out of it. you can use the String.prototype.split() command to split the input value by a comma, or I'm still missing something?
Thank you. I'm very new to React and any programming, so still trying to figure out how to apply in code what I'm thinking.
@CGermain I've edited my answer, see if that helps you. the only problem with this is that the use might not enter in the right format and you'll get undefined. maybe consider an autocomplete input here.
0

I was able to solve this using the recommendation from @laserany and from this article. Instead of having two variables, I just created an array that splits the user input of "location" on the Form. The input forces a user to add text in the format (xxx , xxx) or it will not make the call, however, I need to add input validation where a user enters something like (fdsajio , fdsaf) as this will trigger an Unhandled Rejection (TypeError): Cannot read property 'country' of undefined

App.js (portion of code changed)

  async function fetchData(e) {
    const [city, country] = e.target.elements.location.value.split(', ')
       e.preventDefault()

    const apiData = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city},${country}&APPID=${APIKEY}`)
      .then( res => res.json())
      .then(data => data)

Form.jsx (portion of code change)

        <input
            id="location"
            name="location"
            placeholder="City, Country"       
          />
          </form>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.