I am trying to bind the value from an event from select option tag which has data fetched from mongodb for locations which is populated on the select dropdown during componentDidMount() lifecycle method call.
I want to achieve a functionality in which when I select a value from select drop the corresponding values from other api (restaurants) should get populated.
but the problem is fetch url promise does not seem to resolve and does not bind to state.restaurants array to create ul elements in input type text box. here is my code
export default class Vrestauranthome extends Component {
constructor() {
super();
console.log('Home is called vrestaurant');
this.state = {
locations: [],
restaurants: [],
};
}
componentDidMount() {
console.log('Wallpaper componentDidMount getting called....', this.state);
fetch('http://localhost:5252/zomato/locations', { method: 'GET' })
.then((response) => response.json())
.then((data) => this.setState({ locations: data.data }));
}
fetchRestaurants = (event) => {
fetch(`http://localhost:5252/zomato/restaurants/${event.target.value}`, {
method: 'GET',
})
.then((response) => response.json())
.then((data) => {
this.setState({ restaurants: data.data });
console.log(data.data);
});
};
render() {
if (!this.state.locations || !this.state.restaurants) {
return <>Loading data...</>;
}
let locationList =
this.state.locations.length &&
this.state.locations.map((item) => (
<option key={item.name} value={item.city_id}>
{item.name}
</option>
));
let restaurantList = this.state.restaurants.length && (
<ul>
{this.state.restaurants.map((item) => (
<li key={item.name}>{item.name}</li>
))}
</ul>
);
return (
<div className='ContainerHome'>
<div className='location-selector' style={{ paddingLeft: '90px' }}>
<select
className='locationDropdown px-3'
onChange={this.fetchRestaurants}
>
<option value='0' style={{ display: 'none' }}>
Please type a location
</option>
{locationList}
</select>
</div>
<div className='restaurantSelector' style={{ paddingLeft: '90px' }}>
<input
className='searchForRestaurantinputBOX'
type='text'
placeholder=' Search for restaurants'
style={{
paddingLeft: '50px',
fontFamily: 'Poppins',
opacity: '85%',
}}
/>
{restaurantList}
</div>
</div>
);
}
}
when I use fetch method to get the data from url using the event.target.value, it shows the value when I console log it but it seems to not bind with the url used to get data from the mongodb DB using the backend api routes.
this is in mongo db as Locations and Restaurants collections respectively.
I map city_id from locations to Restaurants.city to get values to populate in search input box.
[{"name":"ShalimarBhagh, Delhi","city_id":"1","location_id":"1","country_name":"India"}]
[{"name":"Gulab","city_name":"Delhi","city":"1","area":"11"}]
when I select an option from the drop it just goes of and throws error below: it shows error in the browser: Uncaught TypeError: Cannot read properties of undefined (reading 'length')
here what shows up in the inspect browser when i select something from :

CodePudding user response:
You should check if the data have been loaded before displaying them.
Adding a check in the render method should prevent the error:
render() {
if (!this.state.locations || !this.state.restaurants) {
return <>Loading data...</>;
}
let locationList =
this.state.locations.length &&
this.state.locations.map((item) => (
<option key={item.name} value={item.city_id}>
{item.name}
</option>
));
let restaurantList = this.state.restaurants.length && (
<ul>
{this.state.restaurants.map((item) => (
<li key={item.name}>{item.name}</li>
))}
</ul>
);
...
}
Also, try to change your setState calls like this:
fetch('http://localhost:5252/zomato/locations', { method: 'GET' })
.then((response) => response.json())
.then((data) =>
this.setState({
...this.state,
locations: data.data,
})
);
...
fetch(`http://localhost:5252/zomato/restaurants/${event.target.value}`, {
method: 'GET',
})
.then((response) => response.json())
.then((data) => {
this.setState({ ...this.state, restaurants: data.data });
});
CodePudding user response:
After a lot of tries and also making functional component same like this I found the error.
It should be data => this.setState({restaurants:data.result}). it gets the results back after update.
This is because in backend it return results variable after getting data from mongoose models. Shheesh.
