rgc998
rgc998

Reputation: 331

React-places-autocomplete -- How can i set state for three inputs whenusing autocompleted?

Each PlacesAutoComplete component needs to have inputprops, which will have onChange which points to handleChange but handleChange only setstate for address1 becuase im insure of how to update state for each individual address when each individual input has an address. So in my example i have three PlacesAutoComplete components and i want the first one to setstate for address1, the second one to setstate for address2 and the third one to setstate for address3. How would I change my code so that each individual PlacesAutoComplete sets state for the corresponding address1, address2 or address3?

class AutoCompleteForm extends React.Component {
 constructor() {
  super()
  this.state = {
   address1: '',
   address2: '',
   address3: ''
 }
}


handleChange = (address) => {
  this.setState({
      address1: address, 
    })
  }

render() {
  const inputProps = {
    value: this.state.address,
    onChange: this.handleChange,
    placeholder: "Enter a location"
  }

  return (
    <form onSubmit={this.handleFormSubmit}>
      <PlacesAutocomplete inputProps={inputProps} />
      <PlacesAutocomplete inputProps={inputProps} />
      <PlacesAutocomplete inputProps={inputProps} />
      <button type="submit">Find Midpoint</button>
    </form>
  )
}
} 

export default AutoCompleteForm

Upvotes: 1

Views: 2246

Answers (2)

rohitpaniker
rohitpaniker

Reputation: 715

I had a similar situation too.

How did I solve it? Follow the steps enlisted below:

0) Declare your constructor like this:

constructor(props) {
  super(props);
  this.state = {
    latLngObj: {}
  }
}

1) Declare below function outside render() {}

handleAddressChange = (address, stateName) => {
  this.setState({
    [stateName]: address,
  });
}

2) I had a loop of pre-selected locations so I used it like this:

<Fragment>
            {
              Object.keys(this.props.selectedLocations).map((i) => {
                return(
                  <div key={i} style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
                    <label className="spacer-right">{this.state.selectedLocations[i].label}: </label>
                    <PlacesAutocomplete inputProps={{value: this.state[`address_${this.props.selectedLocations[i].label.toLowerCase()}`], onChange: (address) => {this.handleAddressChange(address, `address_${this.props.selectedLocations[i].label.toLowerCase()}`)}}} />
                  </div>
                )
              })
            }
          </Fragment>

3) Then on click of another button (in my case it was "Finish" button) we can get geocoding to get lat-long of all specified locations above:

let tempLatLngObj = this.state.latLngObj;
Object.keys(this.state).map((key, index) => {
  if(key.startsWith("address_")) {
    geocodeByAddress(this.state[key])
      .then(results => getLatLng(results[0]))
      .then(latLng => {
        tempLatLngObj[key] = latLng;
        this.setState({ latLngObj: tempLatLngObj }, () => {
          if(index === Object.keys(this.state).length-1) {
            // Your AXIOS API call or whatever operation with the final collection of data stored in latLngObj
          }
        })
      })
      .catch(error => console.error('Error', error))
  }
})

I maybe late to the party with this answer but hope this answer would help someone with this same issue in future.

Thanks and best,

Rohit Paniker

Upvotes: 0

Panther
Panther

Reputation: 9408

One way would be to write 3 different functions to handle all 3 different autocomplete like

handleChange1 = (address) => {
  this.setState({
    address1: address, 
  })
 }

handleChange2 = (address) => {
  this.setState({
    address3: address, 
  })
 }

However, the above one would add more code and repeat the same logic. If you can use some pattern then we can use a single function to do the logic. Lets assume your state will address1, address2, address3.

Now lets write a function that will take in two arguments. One is the actual autocompleted address and the other is state name.

handleAddressChange = (address, stateName) => {
  this.setState({
   [stateName]: address, 
  });
}

Now lets modify your render to send the state name

render() {
  const inputProps = {
    value: this.state.address,
    placeholder: "Enter a location"
  }

  return (
    <form onSubmit={this.handleFormSubmit}>
      <PlacesAutocomplete inputProps={inputProps} onChange={(address) => {this.handleAddressChange(address, 'address1')}} />
      <PlacesAutocomplete inputProps={inputProps} onChange={(address) => {this.handleAddressChange(address, 'address2')}} />
      <PlacesAutocomplete inputProps={inputProps} onChange={(address) => {this.handleAddressChange(address, 'address3')}} />
      <button type="submit">Find Midpoint</button>
    </form>
  )
}

Now this would set the respective state when onChange is called.

Upvotes: 2

Related Questions