I have data that looks like this:
// items.json
[
{
"key": 1,
"category": "Fruits",
"colors": [
{
"color": "red",
"favourite": "apple"
},
{
"color": "orange",
"favourite": "orange"
}
]
},
{
"key": 2,
"category": "Vegetables",
"colors": [
{
"color": "orange",
"favourite": "carrot"
},
{
"color": "green",
"favourite": "celery"
}
]
}
]
But it can have an unlimited amount of objects in each array. What I want to do is initially display the categories, which I have done like this:
import Items from './items.json';
// and then I use it in the render method
render() {
var items= items;
return (
{items.map(item =>
<TouchableOpacity
key={item.key}>
<Text>
{item.category}
</Text>
</TouchableOpacity>
)}
)
}
Now when a category is pressed I want to hide the categories and display the colors. And then when the color is pressed I want to hide the colors and display the favourite.
I have tried doing this with if else statements, but it that won't work if the data is replaced, and as I mentioned this json object can be quite large. Please help!
Declare two arrays in your state, one for storing the original data and one for storing the filtered data based on which item was pressed.
state = {
items: items, // original data
data: items, // will filter data and display using .map()
categoryIndex: 0, // index of the selected category
};
Add onPress to your TouchableOpacity and pass the type of the item that was pressed.
{this.state.data.map((item, index) => (
<TouchableOpacity
onPress={() =>
this.onItemPress(
item.category ? 'category' : item.color ? 'color' : 'favourite',
index
)
}
key={item.key}>
<Text>{item.category || item.color || item.favourite}</Text>
</TouchableOpacity>
))}
onItemPress, based on item that was pressed update state.data
onItemPress = (type, index) => {
if (type === 'category') {
this.setState({
data: this.state.items[index].colors,
categoryIndex: index,
});
}
if (type === 'color') {
this.setState({
data: [
{
favourite: this.state.items[this.state.categoryIndex].colors[index]
.favourite,
},
],
});
}
if (type === 'favourite') {
this.setState({
data: this.state.items,
categoryIndex: 0,
});
}
};
DEMO
You need to:
track in your component state what the selected item or color index is so your render function knows when to rerender and what to render.
handle when an item is pressed by adding the onPress prop to your TouchableOpacity and updating the component state as mentioned above
state = {
selectedItemIndex: null,
selectedColorIndex: null,
};
render {
if (this.state.selectedColorIndex) {
// return some jsx using this data below:
// items[this.state.selectedItemIndex].colors[this.state.selectedColorIndex].favourite
}
if (this.state.selectedItemIndex) {
return (
{items[this.state.selectedItemIndex].colors.map(color, i) => (
{/* return jsx here for colors */}
)}
);
}
return (
{items.map((item, i) => (
<TouchableOpacity
key={item.key}
onPress={() => this.setState({ selectedItemIndex: i })}>
<Text>
{item.category}
</Text>
</TouchableOpacity>
))}
)
}
Related
How can I separate the data to make my section list look like how it is in the picture?
https://i.stack.imgur.com/oABMf.png
It depends on the data structure you have. Lets assume you have this kind of data structure:
const data = [
{
id: 1,
text: "Fooo text 1",
description: "Foooo description 1"
},
{
id: 2,
text: "Fooo text 2",
description: "Foooo description 2"
},
]
function ListScreen() {
const sections = []
sections.push({ title: 'Title', data: data });
return (
<SectionList
sections={sections}
renderItem={({ item, index }) => <Text>{item.id}</Text>}
renderSectionHeader={SectionHeader}
keyExtractor={(item, index) => item.id.toString()}
/>
);
}
function SectionHeader({ section: { title } }) {
return (
<View style={styles.sectionHeader}>
<Text>{title}</Text>
</View>
);
}
const styles = StyleSheet.create({
sectionHeader: {
padding: 12,
},
});
I am trying to display same screen with different parameter in react-native. i checked with https://snack.expo.io/#react-navigation/navigate-with-params-v3. its working fine. But i have to display the different data in same screen. My expectation is in tree view structure data have to display like in our normal system tile view folder structure.
Expected Output view:
The view like normal our system folder title structure. C:/user/ReactNative/file .. like tile view.
Ex:
1.FamilyScreen.js
params : Gradpa -> while click Grandpa it will navigate to same page but the data change as 'Father'
FamilyScreen.js
params:Me - While click 'Father' it will navigate to same page but the data as 'Erick and Rose'.
The data will come from service so it may contain some more than children. it will variant. How to pass the particular data in react-native.
const family = [
{
id: 'Grandparent',
name: 'Grandpa',
age: 78,
children: [
{
id: 'Father',
name: 'Father',
age: 30,
children: [
{
id: 'Erick',
name: 'Erick',
age: 10,
},
{
id: 'Rose',
name: 'Rose',
age: 12,
},
],
},
],
},
]
Thanks
Finaly its working, here my code is
constructor(props) {
super(props)
this.state = {
res:family,
}
this.getNestedData = this.getNestedData.bind(this);
}
getNestedData (item) {
var data;
Object.keys(item).map((propKey) => {
if ( propKey === 'children'){
data=item[propKey]
}
})
this.props.navigation.push('GridScreen',{
data:data
});
}
Item = ({ item }) => {
return (
<View style={styles.item}>
<Text style={styles.title} onPress={this.getNestedData.bind(this,item)}>{item.name}</Text>
</View>
);
}
render() {
const { navigation } = this.props;
const data = navigation.getParam('data', this.state.res);
return (
<View>
<FlatList
data={data }
renderItem={({ item }) => <this.Item item={item} />}
keyExtractor={item => item.id}
numColumns={3}
/>
</View>
)
}
}
I am trying to fetch and display the data from API. Below response i am getting from the API. I want to show the value of "Name" from details array. Kindly help me to resolve this. i have tried below code
{
"Success":1,
"data":[
{
"Date":"2019-11-08",
"Details":[
{
"Name":"Name 1",
"Id":72
},
{
"Name":"Name 2",
"Id":73
}
]
},
{
"Date":"2019-11-09",
"Details":[
{
"Name":"Name 3",
"Id":72
},
{
"Name":"Name 4",
"Id":73
}
]
}
]
}
Javascript map function can be used for nested iteration.
Consider your data is stored in state as data.
If response is received in a variable named response you can set state as
this.setState({ data : response.data })
Then you can use the below code snippet to iterate through nested object values
{
this.state.data.map((dat, index) => { //Iterate through your data
return (
<View style={styles.selectedCh} key={"outer-" + index}>
<Text>{dat.Date}</Text>
{
dat.Details.map((inner, indexInner) => { //Iterate through inner Details
return (
<View style={{ flex: 1 }} key={"inner-" + indexInner} >
<Text>{inner.Id}</Text>
<Text>{inner.Name}</Text>
</View>
)
})
}
</View>
)
})
}
I have a structure json like this:
"diagnosis": [{
"name": "kode",
"value": [
{"value": "kode1"},{"value": "kode2"},{"value": "kode3"}
]},
{
"name": "Primary Category",
"value": [
{"value": "PriCat1","id": "kode1"},
{"value": "PriCat2","id": "kode2"},
{"value": "PriCat3","id": "kode3"}
]},
{
"name": "Location",
"value": [
{"value": "Loc1","id": "kode1"},
{"value": "Loc2","id": "kode2"},
{"value": "Loc3","id": "kode3"}
]}
]
and for now, I can rendering those json with this code:
renderingMenu(){
var tempListCheckBox = this.state.diagnosis.map(function(item,index){
let data = item.value;
return(
<View>
<Text style={[global.global.Text, {padding:DeviceWidth*0.02}]}>{item.name} :</Text>
{/* https://github.com/n4kz/react-native-material-dropdown */}
<Dropdown
dropdownOffset={{top:5}}
containerStyle={{borderWidth:1, borderColor:'lightgrey', borderRadius:50, width:DeviceWidth*0.8, paddingLeft:DeviceWidth*0.02}}
rippleCentered={true}
inputContainerStyle={{ borderBottomColor: 'transparent' }}
data={data}
valueExtractor={({value})=> value}
onChangeText={(value)=>{this.onChangeTextPress(item.name, value)}}
/>
</View>
)
}.bind(this))
return tempListCheckBox;
}
here's the result of my code:
But I need to handle when the kode: label already selected with the value kode1, all the rest of dropdown will auto selected, like Primary Category value = PriCat1, and Location value = Loc1
Example:
I've spent a couple hours to find any code, but still no luck,
anyone have an idea how to do that?
Edited:
onChangeTextPress(key, value){
this.state.selected[key] = value;
this.setState({selected: this.state.selected});
console.log(this.state.selected);
}
To set a value for the dropdown component you need to use value prop and in your onChangeText you need to set selected value again. You are already setting the value in your state but with a small mistake. You shouldn't be mutating state directly. You can use functional setState.
Example
onChangeTextPress(key, value){
this.setState((prevState) => {
let selected = Object.assign({}, prevState.selected);
selected[key] = value;
return { selected };
}, () => {
// because setState is async you need to use a callback
// to be sure of the state set before using a state value
console.log(this.state.selected);
});
}
//...
renderingMenu(){
var tempListCheckBox = this.state.diagnosis.map(function(item,index){
let data = item.value;
return(
<View>
<Text style={[global.global.Text, {padding:DeviceWidth*0.02}]}>{item.name} :</Text>
{/* https://github.com/n4kz/react-native-material-dropdown */}
<Dropdown
dropdownOffset={{top:5}}
containerStyle={{borderWidth:1, borderColor:'lightgrey', borderRadius:50, width:DeviceWidth*0.8, paddingLeft:DeviceWidth*0.02}}
rippleCentered={true}
inputContainerStyle={{ borderBottomColor: 'transparent' }}
data={data}
valueExtractor={({value})=> value}
onChangeText={(value)=>{this.onChangeTextPress(item.name, value)}}
// set value from state if its set
// or use default as first value from the data
value={this.state.selected[item.name] || data[0].value}
/>
</View>
)
}.bind(this))
return tempListCheckBox;
}
render(){
var borderStyle=this.props.isSelected?
{ borderBottomWidth:2, borderColor:'#333'}:
{ borderBottomWidth:0, borderColor:'#333'};
var displayImage=this.props.isSelected?
this.props.selectedImg:
this.props.unSelectedImg;
return (
<TouchableHighlight
underlayColor='#999'
onPress={()=>this.onPressHandler()}
style={styles.container}>
<View style={[styles.content,borderStyle]}>
<Image style={styles.image}
source={displayImage}/>
</View>
</TouchableHighlight>
);
}
the above code is used to update the border style and display image,when the button was selected
but only the border style changed and the image doesn't change.
but if i remove the following code,the image will change. Seems that it only updated one component not all the related items.
var borderStyle=this.props.isSelected?
{ borderBottomWidth:2, borderColor:'#333'}:
{ borderBottomWidth:0, borderColor:'#333'};
Is there anybody know this issue?
the parent component code is following:
var TabBar=React.createClass({
buttons:
[
0,1,2,3
],
selectedImage:
[
require('./../../../images/toolBar/selected/categories.png'),
require('./../../../images/toolBar/selected/Article.png'),
require('./../../../images/toolBar/selected/Stores.png'),
require('./../../../images/toolBar/selected/Me.png')
],
unSelectedImage:
[
require('./../../../images/toolBar/unSelected/categories.png'),
require('./../../../images/toolBar/unSelected/Article.png'),
require('./../../../images/toolBar/unSelected/Stores.png'),
require('./../../../images/toolBar/unSelected/Me.png')
],
getDefaultProps: function() {
return {
style:null
};
},
getInitialState: function() {
return {
selectedIndex:0
};
},
onSelectedHandler(index){
this.setState({
selectedIndex:index
});
},
gerenateButtons(){
var items=[];
var parent=this;
this.buttons.map(function(index){
var item=(
<TabBarBtn
key={index}
index={index}
selectedImg={parent.selectedImage[index]}
unSelectedImg={parent.unSelectedImage[index]}
isSelected={parent.state.selectedIndex==index}
onSelected={id=>{parent.onSelectedHandler(id)}}/>
);
items.push(item);
});
return items;
},
render(){
return (
<View style={[styles.container,this.props.style]}>
{this.gerenateButtons()}
</View>
);
}
});
Thanks in advance