'How to get a certain data in the second autocomplete input that depend on what typed in the first input in React.js?

Okay, so I don't know how to properly express my simple problem because of how simple it is, I guess.

Basically, I have an autocomplete done by me in my React project.. I have two inputs "Country" and "City". When I type a country my autocomplete works great giving me suggestions but now I have to make the same for my second input so it would give me a list of cities that depends on which country is typed in the "Country" input...

"United Kingdom" => "London, Birmingham, Bighton etc."

How can I do that? Thank you!

P.S. I already have all the lists of countries and cities, I just don't know how to make the second input to depend on an information in the first one.

Code here

Autocomplete.jsx https://github.com/lembas-cracker/Weather-app/blob/master/src/Autocomplete.jsx

Form.jsx https://github.com/lembas-cracker/Weather-app/blob/master/src/Form.jsx



Solution 1:[1]

P.S. I already have all the lists of countries and cities, I just don't know how to make the second input to depend on an information in the first one.

If you know which country the city belongs to (perhaps via a key in the city object), you could run a simple filter function to remove any cities that don't belong to that country.

this.state = {
    selectedCountry: 'London',
};

const cities = [
    { name: "Toronto", country: "Canada" },
    { name: "London", country: "United Kingdom" }
];

const filteredCities = cities.filter(city => {
    return city.country !== this.state.selectedCountry;
});

On your city input field make sure to create an onBlur function to will run the filter on your cities list once the user leaves that input field.

Solution 2:[2]

Made a quick example. Did you mean smth like this? Since you haven't provided any part of your source code, I used plain HTML select for the demo.

https://jsfiddle.net/arfeo/n5u2wwjg/204186/

class App extends React.Component {
    constructor() {
    super();

    this.state = {
        countryId: 1,
    };
  }

  onCountryChange(countryId) {
    this.setState({ countryId: parseInt(countryId) });
  }

    render() {
    return (
        <div>
        <Input
          key="countriesInput"
          type="countries"
          countryId={this.state.countryId}
          onChange={(countryId) => this.onCountryChange(countryId)}
        />
        <Input
          key="citiesInput"
          type="cities"
          countryId={this.state.countryId}
        />
      </div>
    );
  }
}

class Input extends React.Component {
    constructor() {
    super();

    this.selectRef = null;
  }

    renderOptions() {
    const countries = [
        {
        id: 1,
        name: 'England',
      },
      {
        id: 2,
        name: 'Germany',
      },
      {
        id: 3,
        name: 'France',
      },
    ];

    const cities = [
        {
        countryId: 1,
        cities: [
            {
            id: 1,
            name: 'London',
          },
            {
            id: 2,
            name: 'Liverpool',
          },
          {
            id: 3,
            name: 'Salisbury'
          }
        ],
      },
      {
        countryId: 2,
        cities: [
            {
            id: 4,
            name: 'Berlin',
          },
          {
            id: 5,
            name: 'Frankfurt',
          },
        ],
      },
      {
        countryId: 3,
        cities: [
            {
            id: 6,
            name: 'Paris',
          },
        ],
      },
    ];

    switch (this.props.type) {
        case 'countries': {
        return countries.map((country) => (
          <option
            key={country.id.toString()}
            value={country.id}
          >
            {country.name}
          </option>
        ));
      }
        case 'cities': {
        const citiesMap = cities.filter((city) => city.countryId === this.props.countryId);

        if (citiesMap && citiesMap[0]) {
            const citiesList = citiesMap[0].cities;

          if (citiesList) {
            return citiesList.map((city) => (
              <option
                key={city.id.toString()}
                value={city.id}
              >
                {city.name}
              </option>
            ));
          }
        }

        return null;
      }
      default: return null;
    }
  }

    render() {
    return (
        <select name={this.props.type} ref={(ref) => this.selectRef = ref} onChange={() => this.props.onChange(this.selectRef.value)}>
        {this.renderOptions()}
      </select>
    );
  }
}

ReactDOM.render(<App />, document.querySelector("#app"))

UPDATE

  1. Make your Form component stateful.

  2. Add a state property for countries in Form (let it be countryId).

  3. Pass this property as a prop into the second Autocomplete component.

  4. When the first Autocomplete changes, change the countryId of the Form.

Solution 3:[3]

I've done something similar which may help you.

The Object.keys(instutiontypes) you could use to have an array of countries, instead. Then inside of those values, you can have an array of objects. You could have the cities here, e.g. {value: "Manchester", "label: Manchester", phoneExt: "0114"}

const instutiontypes =  {
Kindergarten: [
    { value: "PreK", label: "PreK" },
    { value: "K1", label: "K1" },
    { value: "K2", label: "K2" },
    { value: "K3", label: "K3" },
  ],
  "Primary School": [
    { value: "Grade 1", label: "Grade 1" },
    { value: "Grade 2", label: "Grade 2" },
    { value: "Grade 3", label: "Grade 3" },
    { value: "Grade 4", label: "Grade 4" },
    { value: "Grade 5", label: "Grade 5" },
    { value: "Grade 6", label: "Grade 6" },
  ],
}

To have the options in my input, I use Object.keys(instutiontypes) to get ['Kindergarten','Primary School']

Then, to get the array of ages to give to my secondary dropdown, I have written this code:

const types = ['Selection1', 'Selection2']

  const agesList = [];

  for (let i = 0; i < types.length; i++) {
    Object.values(institutionTypes[types[i]]).map(({ label }) =>
      agesList.push(label)
    );
  }

This way, the ages dropdown list is dependent on the values passed to institutionTypes.

I'm using mui's <Autocomplete /> components to make them be search dropdowns, with the prop options for the arrays.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ALazenka
Solution 2
Solution 3