I'm trying to make an autocomplete/autosuggest search bar from Material-UI through an API response. Here's the codebase annex by annex.
We are defining our options of the autosuggest search bar from the given coinlist API provided. We are defining our options state as well here.
function MainInput() {
const classes = useStyles();
const [options, setOptions] = useState([]);
useEffect(() => {
axios
.get(`https://min-api.cryptocompare.com/data/all/coinlist`)
.then((res) => {
console.log(res.data.Data);
setOptions(res.data.Data);
})
.catch((err) => {
console.log(err);
});
}, []);
Now in the docs from Material-UI for the <Autocomplete /> component. We are supposed to defined our options within the options prop. Theoretically, everything should be fine right? Well, the react app loads fine at first but when I click the searchbar everything disappears from the screen. Can anyone pitch any ideas?
return (
<div className={classes.root}>
<Autocomplete
id='combo-box-demo'
options={options}
getOptionLabel={(options) => options}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label='Combo box' variant='outlined' />
)}
/>
</div>
);
}
Here is what the raw API response looks like for you guys to have an idea.
"Response": "Success",
"Message": "Coin list succesfully returned!",
"Data": {
"42": {
"Id": "4321",
"Url": "/coins/42/overview",
"ImageUrl": "/media/35650717/42.jpg",
"ContentCreatedOn": 1427211129,
"Name": "42",
"Symbol": "42",
"CoinName": "42 Coin",
"FullName": "42 Coin (42)",
"Algorithm": "Scrypt",
"ProofType": "PoW/PoS",
"FullyPremined": "0",
"TotalCoinSupply": "42",
"BuiltOn": "N/A",
"SmartContractAddress": "N/A",
"DecimalPlaces": 0,
"PreMinedValue": "N/A",
"TotalCoinsFreeFloat": "N/A",
"SortOrder": "34",
"Sponsored": false,
"Taxonomy": {
"Access": "",
"FCA": "",
"FINMA": "",
"Industry": "",
"CollateralizedAsset": "",
"CollateralizedAssetType": "",
"CollateralType": "",
"CollateralInfo": ""
},
"Rating": {
"Weiss": {
"Rating": "",
"TechnologyAdoptionRating": "",
"MarketPerformanceRating": ""
}
},
"IsTrading": true,
"TotalCoinsMined": 41.9999522,
"BlockNumber": 200520,
"NetHashesPerSecond": 0,
"BlockReward": 0,
"BlockTime": 0
},{...}
There is an issue with your Data coming from API RESPONSE.
According to Material-UI, the parameter you pass to options should be in an Array but your one is an Object.
Please convert the Data type to Array instead of Object and it will work!
return (
<div className={classes.root}>
<Autocomplete
id='combo-box-demo'
options={options} // this should be in An Array
getOptionLabel={(option) =>option} //go through one option at a time
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label='Combo box' variant='outlined' />
)}
/>
</div>
);
}
Please check the Official Docs of Material-UI
https://material-ui.com/components/autocomplete/
Related
Been trying all morning and for the life of me I can't get individual array data to be displayed from my API. I am trying to display one body of text from an array at a time, and can only get it to output all at once. Had it working when the data was in JSON format but now its in an array I'm struggling to make it work.
My code:
componentDidMount() {
axios
.get(
"API_DATA"
)
.then((res) => {
let data = res.data
this.setState({ data, loading: false });
console.log(data)
});
}
render() {
if (this.state.loading) {
return <Loader />
}
// return table if loading is false
// handling error goes with the same logic
// table will only render if loading is false
else
return (
this.state.data.data).map((item) => (
<>
<p key={item.id}>{item.title}</p>
</>
))
}
}
I previously used added [0] or [1] etc to determine which element I wanted to display and this worked very nicely however if I try this.state.data.data[0]).map((item) => ( It states it is not a function.
Expected output of API:
{
"data": [
{
"id": 9,
"status": "published",
"body": "TEST1",
"availability": "internal",
"title": "Test1",
"posted_by": "Tester"
},
{
"id": 10,
"status": "published",
"body": "TEST",
"availability": "internal",
"title": "TEST2",
"posted_by": "Tester"
},
I want to fetch data from API and trying to use in index.js
Error:
TypeError: Cannot read properties of undefined (reading 'icon')
When I console.log it prints
Empty Array of index.js > response data of weatherSlice.js > and finally response data of index.js as an array
I was getting undefined error and tried this and kinda worked .
{getCity.length !== 0 && (
<Typography variant="h6" component="div">
<div>Wind : {getCity.current.gust_kph} kph</div>
<div>Pressure: {getCity.current.pressure_in} in</div>
</Typography>
)}
But this time it gives same error on this block
{getCity.length !== 0 && (
<Grid item xs={3} sx={{mb:3}}>
<div className="label">{getDate()}</div>
<div className="label"> <img src={`${getCity.forecast.forecastday[1].condition.icon}`} alt="" /></div> // Gives undefined (reading"icon")
<div className="label" >22 C</div>
</Grid>)}
Index.js
const dispatch = useDispatch();
const [selectedCity, setSelectedCity] = useState('Ankara');
const getCity = useSelector((state) => state.weather.item);
const [datee , setDate ] = useState('');
useEffect(() => {
dispatch(fetchDefault(selectedCity))
setDate(getDate())
}, [dispatch])
weatherSlice
export const fetchDefault = createAsyncThunk('weather/getWeather', async (selectedCity) => {
const res = await axios(`http://api.weatherapi.com/v1/forecast.json?key=ebb6c0feefc646f6aa6124922211211&q=${selectedCity}&days=10&aqi=no&alerts=no
`)
return res.data});
export const weatherSlice = createSlice({
name: "weather",
initialState : {
item : [],
},
reducers:{},
extraReducers:{
[fetchDefault.fulfilled]: (state , action) => {
state.item = action.payload;
console.log(state.item)
},
[fetchDefault.pending]: (state , action) => {
console.log("sadsad")
}
}
After the state.weather.item state is populated it's now an object, not an array. The initial condition getCity.length !== 0 works/passes because getCity.length is undefined and undefined !== 0 evaluates true. The issue is occurring after you start accessing into the state.
The fetched city data is an object with location, current, and forecast properties.
// 20211114135700
// https://api.weatherapi.com/v1/forecast.json?key=ebb6c0feefc646f6aa6124922211211&q=seattle&days=10&aqi=no&alerts=no
{
"location": {
"name": "Seattle",
"region": "Washington",
"country": "United States of America",
"lat": 47.61,
"lon": -122.33,
"tz_id": "America/Los_Angeles",
"localtime_epoch": 1636927019,
"localtime": "2021-11-14 13:56"
},
"current": {
"last_updated_epoch": 1636926300,
"last_updated": "2021-11-14 13:45",
"temp_c": 16.1,
"temp_f": 61.0,
"is_day": 1,
"condition": {
"text": "Light rain",
"icon": "//cdn.weatherapi.com/weather/64x64/day/296.png",
"code": 1183
},
"wind_mph": 13.6,
"wind_kph": 22.0,
"wind_degree": 190,
"wind_dir": "S",
"pressure_mb": 1014.0,
"pressure_in": 29.94,
"precip_mm": 1.0,
"precip_in": 0.04,
"humidity": 90,
"cloud": 100,
"feelslike_c": 16.1,
"feelslike_f": 61.0,
"vis_km": 3.2,
"vis_miles": 1.0,
"uv": 4.0,
"gust_mph": 18.8,
"gust_kph": 30.2
},
"forecast": {
"forecastday": [
{
"date": "2021-11-14",
"date_epoch": 1636848000,
"day": {
"maxtemp_c": 16.2,
"maxtemp_f": 61.2,
"mintemp_c": 11.5,
"mintemp_f": 52.7,
"avgtemp_c": 14.9,
"avgtemp_f": 58.8,
"maxwind_mph": 16.1,
"maxwind_kph": 25.9,
"totalprecip_mm": 21.1,
"totalprecip_in": 0.83,
"avgvis_km": 9.3,
"avgvis_miles": 5.0,
"avghumidity": 93.0,
"daily_will_it_rain": 1,
"daily_chance_of_rain": 99,
"daily_will_it_snow": 0,
"daily_chance_of_snow": 0,
"condition": {
"text": "Heavy rain",
"icon": "//cdn.weatherapi.com/weather/64x64/day/308.png",
"code": 1195
},
"uv": 1.0
},
"astro": {
...
},
"hour": [
...
]
},
...
]
}
}
You are attempting to render the forecast, but here's where the code really goes sideways. You're assuming there's at least 2 elements (i.e. the getCity.forecast.forecastday.length>= 2), and then if there is, assume theres aconditionproperty. When there isn't andgetCity.forecast.forecastday[1].condition` is undefined, this is the error you are seeing.
From what I can tell, the condition property is nested within a day field. Since it's unclear what properties are guaranteed to exist in the response data your best bet is to:
First make sure you are accessing into the correct path
Use null-checks/guard-clauses or Optional Chaining operator to prevent accidental null/undefined accesses
The updated object property path is as follows:
getCity.forecast.forecastday.[1].day.condition.icon
If any of these are potentially undefined or otherwise not returned in the data, the corrected access using the Optional Chaining operator is as follows:
getCity.forecast?.forecastday?.[1]?.day?.condition?.icon
Which is the equivalent null-check/guard-clause version of:
getCity.forecast
&& getCity.forecast.forecastday
&& getCity.forecast.forecastday[1]
&& getCity.forecast.forecastday[1].day
&& getCity.forecast.forecastday[1].day.condition
&& getCity.forecast.forecastday[1].day.condition.icon
Use the same sort of check for the current weather data:
{getCity.current && (
<Typography variant="h6" component="div">
<div>Wind : {getCity.current.gust_kph} kph</div>
<div>Pressure: {getCity.current.pressure_in} in</div>
</Typography>
)}
Finally, update the initial state for the weather slice to match the data invariant, it should be an object.
initialState : {
item : {},
},
I am mapping over some data that I am getting from a api however when i try to add the filter function i get 'currencyData.includes is not a function'
I have also tried just hard coding the array but it also still doesnt work?
I have a loading state for when i fetch data from the api which holds code from being run but i have removed it from this example as its not getting data from the api below.
The simplified version is here...
ARRAY
var items = [
{
"id": 1,
"productName": "shoes",
"productIdentifier": "CL001",
"productDescription": "adidas kicks boir",
"productPrice": 2000,
"productStock": 200,
"created_at": "2020-51-28",
"updated_at": null
},
{
"id": 2,
"productName": "burger",
"productIdentifier": "FD001",
"productDescription": "charsiu berger",
"productPrice": 2000,
"productStock": 200,
"created_at": "2020-51-28",
"updated_at": null
}
]
return(
{items.filter(currencyInfo => currencyInfo.includes("FD001")).map((value, index) => {
console.log(value)
return(
<h1 key={index}>{value}</h1>
)
})}
)
currencyInfo is not an array, you can not call includes on it
Here is my suggestion:
return(
{items.filter(currencyInfo => currencyInfo.productIdentifier === "FD001").map((value, index) => {
console.log(value)
return(
<h1 key={index}>{value}</h1>
)
})}
)
More about includes()
The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate. Check this Doc
But in items.filter(currencyInfo => currencyInfo.includes("FD001")), type of currencyInfo isn't array but object.
So you should use currencyInfo.productIdentifier.includes()
I have a JSON request, that returns a JSON objects;
{
"kind": "youtube#searchListResponse",
"etag": "zy8y9DkaOiYwKh0aStoEqOU_knU",
"nextPageToken": "CBQQAA",
"regionCode": "GB",
"pageInfo": {
"totalResults": 40,
"resultsPerPage": 20
},
"items": [
{
"kind": "youtube#searchResult",
"etag": "tvnouv0ap06XQKjt95dVECc_VZ4",
"id": {
"kind": "youtube#video",
"videoId": "Qiyk-s60rgo"
},
"snippet": {
"publishedAt": "2020-04-30T10:00:46Z",
"channelId": "UCa_6KiOjxm6dEC_mMRP5lGA",
"title": "Derby Futsal Club - Goal of the Season 2019/20 | Tom Gascoyne vs Birmingham",
"description": "Derby Futsal Club's Goal of the Season as voted for by the public went to Tom Gascoyne for his goal against Birmingham in the National Futsal Series on 3rd ...",
"thumbnails": {
"default": {
"url": "https://i.ytimg.com/vi/Qiyk-s60rgo/default.jpg",
"width": 120,
"height": 90
},
"medium": {
"url": "https://i.ytimg.com/vi/Qiyk-s60rgo/mqdefault.jpg",
"width": 320,
"height": 180
},
"high": {
"url": "https://i.ytimg.com/vi/Qiyk-s60rgo/hqdefault.jpg",
"width": 480,
"height": 360
}
},
"channelTitle": "Derby Futsal",
"liveBroadcastContent": "none",
"publishTime": "2020-04-30T10:00:46Z"
}
},
I'm reading the JSON like so;
useEffect(() => {
fetch(playertype(typeOfProfile))
.then((response) => response.json())
.then((json) => {
setData(json)
})
.catch((error) => console.error(error))
.finally(() => setLoading(false));
}, []);
return (
<View style={styles.body}>
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={data[0]}
horizontal={true}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<View style={stylesB.container}>
<Image style={styles.img} source={{ uri: chkValueI(item.items.snippet.medium.url) }} />
</View>
)}
/>
)}
</View>
);
};
I'm reading the data as data[0] so I hit the first object, and then finding the property I want (the image) by using item.items.snippet.medium.url, but this doesn't return anything.
My question is;
Can I specify the object I want to get by using data[0] and then reference a property using item.items.snippet.medium.url?
Can I specify the object I want to get by using data[0] and then
reference a property using item.items.snippet.medium.url?
Flat list requires a data array so you dont need a flatlist to display a single item. You can simply use the renderItem function and pass the first item.
item.items.snippet.medium.url
Here the items is an array so you should use something like below to access the item. Better check the array length before doing this. Or go for a map to map the values.
item.items[0].snippet.medium.url
Hope this helps.
I fetch an api on componentDIdMount() then store the json to a state then I pass that state as a prop, I have no problem showing the data except on arrays.
<Component details={this.state.details} />
json:
{
"adult": false,
"backdrop_path": "/qonBhlm0UjuKX2sH7e73pnG0454.jpg",
"belongs_to_collection": null,
"budget": 90000000,
"genres": [
{
"id": 28,
"name": "Action"
},
{
"id": 878,
"name": "Science Fiction"
},
{
"id": 35,
"name": "Comedy"
},
{
"id": 10751,
"name": "Family"
}
]
}
then I try to map the genres:
<div className={style.genre}>
{details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
</div>
But then I get Cannot read property 'map' of undefined, I don't know why this is happening because I'm able to do details.budget
It's trying to read data before you get the result from api.
so write the map function as
{details&&details.genres&&details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
In react Initially when component is mounted, render() function is called and then componenentDidMount() is called in which you fetch data. So Initially details is empty. So you need to write the condition.