I'm having some trouble rendering an image onto a section list from a JSON file even though I am having no trouble with the text data.
here is my JSON DATA:
{
"title" : "Friday",
"data":
[
{
"artist": "artist 1",
"stage": "The Oak",
"Instagram": "insta",
"Spotify": "spot",
"date": "10/8/2021",
"Image": "../assets/art1.jpg",
"Time" : "4:30PM - 5:00 PM"
},
{
"artist": "artist 2",
"stage": "The Oak",
"Instagram": "insta",
"Spotify": "spot",
"date": "10/8/2021",
"Image": "../assets/art2.jpg",
"Time" : "5.00PM - 5:30 PM"
}
]},
I am aware that you have to use the require function to render it but I just cant seem to get it right.
Here is the SectionList:
<SectionList
sections={data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (<View style={styles.listItemView}>
<Image style={styles.image} source={require(item.Image)} />
<View>
<Text style={styles.listItem}>{item.artist}</Text>
<Text style={styles.listItemTime} >{item.Time}</Text>
</View>
</View>)}
renderSectionHeader={({ section }) => (
<View style={styles.item}>
<Text style={styles.title}>{section.title}</Text>
</View>)}
/>
Any help is welcome. Please let me know if I need to add addition info!
Thanks!
You can use a if-else or switch statement to get the image you want to use.
const getArtImage = (artName) => {
switch (artName){
case 'art1':
return require('../assets/art1.jpg');
case 'art2':
return require('../assets/art2.jpg');
default:
return require('../assets/defaultArt.jpg');
}
}
and use this getArtImage function in your Image component.
<Image style={styles.image} source={getArtImage(item.Image)} />
item.Image should be like art1, art2 etc.
--
If your json is a local file, you can convert it to a js file.
export default {
title: "Friday",
data: [
{
artist: "artist 1",
stage: "The Oak",
Instagram: "insta",
Spotify: "spot",
date: "10/8/2021",
Image: require("../assets/art1.jpg"),
Time: "4:30PM - 5:00 PM",
},
{
artist: "artist 2",
stage: "The Oak",
Instagram: "insta",
Spotify: "spot",
date: "10/8/2021",
Image: require("../assets/art2.jpg"),
Time: "5.00PM - 5:30 PM",
},
],
};
Related
EDIT: None of the solutions below worked for me as they were so after fiddling with ido ben ami's one I got this to work:
{
array.map(project =>
<Box>
<Typography variant="subtitle1" sx={{fontWeight: 'bold', ml: 2}}
value={Object.keys(project)[0]}>{Object.keys(project)[0]}</Typography>
{
Object.entries(project)[0][1].map(ticket =>
<MenuItem sx={{ml: 3}} value={ticket}>{ticket}</MenuItem>)
}
</Box>
)
}
I had originally used fragments instead of Box but Material UI doesn't like that for Select. If I left out one of these two it didn't work because the 2 components being generated are not the same.
The data from my backend is as such (number of projects/tickets varies obviously):
[
{
"Project 1": [
"Ticket 1",
"Ticket 2",
"Ticket 3",
]
},
{
"Project 2": [
"Ticket 4"
"Ticket 5"
"Ticket 6"
]
}
]
I need to map over it to generate items for my Select component. This is the outcome I'm after but I can't figure out how to do it with Object.entries or Object.keys/Object.values:
<Typography variant="subtitle1" sx={{fontWeight: 'bold', ml: 2}} value="Project 1">Project 1</Typography>
<MenuItem sx={{ml: 3}} value="Ticket 1">Ticket 1</MenuItem>
<MenuItem sx={{ml: 3}} value="Ticket 2">Ticket 2</MenuItem>
<MenuItem sx={{ml: 3}} value="Ticket 3">Ticket 3</MenuItem>
<Typography variant="subtitle1" sx={{fontWeight: 'bold', ml: 2}} value="Project 2">Project 2</Typography>
<MenuItem sx={{ml: 3}} value="Ticket 4">Ticket 4</MenuItem>
<MenuItem sx={{ml: 3}} value="Ticket 5">Ticket 5</MenuItem>
<MenuItem sx={{ml: 3}} value="Ticket 6">Ticket 6</MenuItem>
try this
<Box>
{array.map((project, projectIndex) => (
<Box key={projectIndex}>
{console.log(Object.entries(project))}
<Typography
variant="subtitle1"
sx={{ fontWeight: 'bold', ml: 2 }}
value={Object.entries(project)[0][0]}>
{Object.entries(project)[0][0]}
</Typography>
{Object.entries(project)[0][1].map((ticket, ticketIndex) => (<MenuItem key={ticketIndex} sx={{ ml: 3 }} value={ticket}>{ticket}</MenuItem>))}
</Box>
))}
</Box>
but if you have access to make changes in the backend I will recommend to save the data like this:
[
{
"projectName": "Project 1"
"tickets": [
"Ticket 1",
"Ticket 2",
"Ticket 3",
]
},
{
"projectName": "Project 2"
"tickets": [
"Ticket 4"
"Ticket 5"
"Ticket 6"
]
}
]
You have an array of objects. In this objects you have only one properties. That properties is another array of string.
I do not know what is component Typography exatly doing and will be my solution good for your code and optimization but.
you can try somthing like this:
Before rendering component (not JSX)
let backEndValue = [
{
"Project 1": [
"Ticket 1",
"Ticket 2",
"Ticket 3",
]
},
{
"Project 2": [
"Ticket 4",
"Ticket 5",
"Ticket 6",
]
}
]
const [title,setTitle] = useState('');
const [subTitle,setSubTitle] = useState('');
setProjects = [];
Object.keys(backEndValue).map((prop) => {
return setProjects.push(backEndValue[prop]);
})
setProjects.map((prop)=>{
const temp = Object.keys(prop);
const tempT = prop[temp];
setTitle(temp);
setSubTitle(tempT);
})
In rendering (JSX)
{
title.map((prop,index)=>{
return <Typography key={index} variant="subtitle1" sx={{fontWeight: 'bold', ml: 2}} value={prop}>{prop}</Typography>
})
}
{
subTitle.map((prop,index)=>{
return <MenuItem key={index} sx={{ml: 3}} value={prop}>{prop}</MenuItem>
})
}
I'm getting a json object that looks like this:
Array [
Object {
"department": "department 1",
"formName": "form 1",
"id": 1,
},
Object {
"department": "department 1",
"formName": "form 2",
"id": 2,
},
Object {
"department": "deparment 1",
"formName": "form 3",
"id": 3,
},
Object {
"department": "department 1",
"formName": "form 4",
"id": 4,
},
Object {
"department": "department 2",
"formName": "form 5",
"id": 5,
},
]
as you can see, there are only 2 unique departments, but 5 different forms. 4 of the forms belong to department 1 and the other remaining form belongs to department 2
I am trying to render 2 buttons that look something like this:
department 1
form 1
form 2
form 3
form 4
department 2
form 5
this is the flat list component I have at the moment
<FlatList
data={this.state.dataList}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => {
return (
<TouchableWithoutFeedback
onPress={console.log("touched")}
style={styles.clearBtn}
>
<Text style={styles.clearBtnText}>{item.department}</Text>
<Text style={styles.clearBtnText2}>{item.formName}</Text>
</TouchableWithoutFeedback>
);
}}
/>
However, this obviously renders 5 buttons that look like this:
department 1
form 1
department 1
form 2
department 1
form 3
department 1
form 4
department 2
form 5
You may want to remodel your data and use a SectionList instead of a FlatList, it looks more fitting for your use case.
The official docs are here, and if we go by their example your data should look something like:
[
{
title: 'Department 1',
data: [{formName: 'form1', id: 1} ,{formName: 'form2', id:2} ...]
},
{
title: 'Department 2',
data: [{formName: 'form5', id: 5}]
}
]
And your SectionList render would look like
<SectionList
sections={this.state.dataList}
keyExtractor={(item) => item.id.toString()}
renderSectionHeader={({ section: { title } }) => (
<Text style={/*Whatever style you want*/}>{title}</Text>
)}
renderItem={({ item }) => {
return (
<TouchableWithoutFeedback
onPress={() => console.log("touched")}
style={styles.clearBtn}
>
<Text style={styles.clearBtnText2}>{item.formName}</Text>
</TouchableWithoutFeedback>
);
}}
/>
Assuming this.state.dataList is the data model I have presented
as #Ron B. suggested, you need to convert your data from flat to section array structure as below.
const flatToSection = (data)=>{
const getDepartmentData = (department,data)=>{
return data.filter(item=> item.department === department)
}
const departments =[...new Set( data.map(el=> el.department))]
const sections = departments.map((department)=>({
title:department,
data :getDepartmentData(department,data)
}))
return sections
}
export default flatToSection
Then replace FlatList with Section list.
Working example - https://snack.expo.dev/#emmbyiringiro/c8a7cd
I am trying to map through some data and display the values from the objects I am mapping through, but it keeps return "[object Object]", usually I just wrap it in JSON.stringify but that isn't working here, what am I doing wrong? Here's my code:
const ListingItem = (props: any) => {
const MOVIE_POSTER_API_URL = "https://image.tmdb.org/t/p/w92/";
const [openMovieDbData, setOpenMovieDbData] = useState<Array<any>>([]);
const [openMovieDbRatings, setOpenMovieDbRatings] = useState([]);
useEffect((): any => {
axios.get(`http://www.omdbapi.com/?t=${props.movie.title}&y=${props.movie.release_date && props.movie.release_date.substr(0, 4)}&apikey=${process.env.REACT_APP_OPEN_MOVIE_API_KEY}`)
.then(response => {
setOpenMovieDbData(response.data);
setOpenMovieDbRatings(response.data.Ratings);
})
.catch((error) => console.log('Open Movie DB HTTP GET Request Error response:', error))
}, [])
return (
<ListItem key={props.movie.id}>
{props.movie.backdrop_path ?
<ListItemAvatar>
<Avatar src={MOVIE_POSTER_API_URL + props.movie.backdrop_path} />
</ListItemAvatar> :
<ListItemIcon>
<Avatar>
<LocalMoviesIcon />
</Avatar>
</ListItemIcon>
}
<ListItemText
primary={props.movie.title}
secondary={`${props.movie.overview} Released in ${props.movie.release_date ? props.movie.release_date.substr(0, 4) : 'N/A'}
${openMovieDbRatings ? openMovieDbRatings.map((rating: any) => <div>{JSON.stringify(rating.Source)}: {JSON.stringify(rating.Value)}</div>) : 'No Reviews'}
Rated: ${openMovieDbData['Rated'] ? openMovieDbData['Rated'] : 'N/A'}
`
}
/>
</ListItem>
)
}
This is an example of what will get returned, in place of [object Object] should be the object values I am trying to access:
Example of response data:
{
"Title": "Braveheart",
"Year": "1995",
"Rated": "R",
"Released": "24 May 1995",
"Runtime": "178 min",
"Genre": "Biography, Drama, History, War",
"Director": "Mel Gibson",
"Writer": "Randall Wallace",
"Actors": "James Robinson, Sean Lawlor, Sandy Nelson, James Cosmo",
"Plot": "Scottish warrior William Wallace leads his countrymen in a rebellion to free his homeland from the tyranny of King Edward I of England.",
"Language": "English, French, Latin, Scottish Gaelic, Italian",
"Country": "USA",
"Awards": "Won 5 Oscars. Another 28 wins & 33 nominations.",
"Poster": "https://m.media-amazon.com/images/M/MV5BMzkzMmU0YTYtOWM3My00YzBmLWI0YzctOGYyNTkwMWE5MTJkXkEyXkFqcGdeQXVyNzkwMjQ5NzM#._V1_SX300.jpg",
"Ratings": [{
"Source": "Internet Movie Database",
"Value": "8.3/10"
}, {
"Source": "Rotten Tomatoes",
"Value": "78%"
}, {
"Source": "Metacritic",
"Value": "68/100"
}],
"Metascore": "68",
"imdbRating": "8.3",
"imdbVotes": "944,923",
"imdbID": "tt0112573",
"Type": "movie",
"DVD": "N/A",
"BoxOffice": "N/A",
"Production": "Icon Entertainment International, Twentieth Century Fox, Ladd Company, Paramount Pictures, B.H. Finance C.V.",
"Website": "N/A",
"Response": "True"
}
i think the issue is here,
secondary={`${props.movie.overview} Released in ${props.movie.release_date ? props.movie.release_date.substr(0, 4) : 'N/A'}
${openMovieDbRatings ? openMovieDbRatings.map((rating: any) => <div>{JSON.stringify(rating.Source)}: {JSON.stringify(rating.Value)}</div>) : 'No Reviews'}
Rated: ${openMovieDbData['Rated'] ? openMovieDbData['Rated'] : 'N/A'}
`}
#1: (main)
${openMovieDbRatings
? openMovieDbRatings.map((rating: any) =>
<div>{JSON.stringify(rating.Source)}: {JSON.stringify(rating.Value)}</div>
)
: 'No Reviews'}
You are mapping openMovieDbRatings and making em ReactElements (aka Objects) by wrapping those inside divs. But, Then u directly pass them to string. This is causing the [object object] thing
#2:
The Rating Object,
"Ratings": [{
"Source": "Internet Movie Database",
"Value": "8.3/10"
}, {
"Source": "Rotten Tomatoes",
"Value": "78%"
}, {
"Source": "Metacritic",
"Value": "68/100"
}],
Here, The Rating Value & Source are strings. So, it unnecessary to JSON.stringify them,
<div>{JSON.stringify(rating.Source)}: {JSON.stringify(rating.Value)}</div>
My Solution,
<ListItemText
primary={props.movie.title}
secondary={
<>
{props.movie.overview} Released in{' '}
{props.movie.release_date
? props.movie.release_date.substr(0, 4)
: 'N/A'}{' '}
{openMovieDbRatings
? openMovieDbRatings.map((rating: any) => (
<div>
{rating.Source}: {rating.Value}
</div>
))
: 'No Reviews'}
Rated:{' '}
{openMovieDbData['Rated'] ? openMovieDbData['Rated'] : 'N/A'}
</>
}
/>
Simply, use React.Fragments.
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/
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.