Absolute react-native noob here. I am struggling with updating the 'selected item'. I'm using this as a piece of dummy data:
this.state = {
branch: '',
completedBy: '',
reportedTo: '',
branchData: {
text: 'Branch',
value: '',
options: [
{code: '0001', name: 'TEST 1', key: 1},
{code: '0002', name: 'TEST 2', key: 2},
{code: '0003', name: 'TEST 3', key: 3},
]
}
};
I then made a separate file for my dropdown component, it looks like this:
super(props);
this.state = {
modalVisible: false
};
}
render() {
return (
<>
<TouchableWithoutFeedback style={styles.refreshBtn} onPress={() => this.setState({ modalVisible: true })} >
<View style={styles.container} >
{
this.props.data.value ?
<Text style={styles.selectedText} >{this.props.data.value}</Text>
:
<Text style={styles.placeholderText} >{this.props.data.text}</Text>
}
<MaterialCommunityIcons name={'chevron-down'} size={30} color={Colors.grey} />
</View>
</TouchableWithoutFeedback>
<Modal
animationType="slide"
visible={this.state.modalVisible}
onRequestClose={() => {
this.setState({ modalVisible: false })
}}
>
<TouchableOpacity onPress={() => this.setState({ modalVisible: false })} style={{ flexDirection: "row", justifyContent: "flex-end", margin: 10, paddingLeft: 50}}>
<Ionicons name="md-close" size={30} />
</TouchableOpacity>
<FlatList
data={this.props.data.options}
keyExtractor={(item) => item.key.toString()}
renderItem={({ item }) => (
<TouchableOpacity style={styles.itemContainer} onPress={() => console.log('tapped'} >
<Text style={styles.itemText}>{item.code + ' ' + item.name}</Text>
</TouchableOpacity>
)}
/>
</Modal>
</>
);
}
}
And then back to my initial file, I am simply calling the component like this:
<DropDownMenu data={this.state.branchData}/>
How do I update the value in the branch data object in order to display the selected branch on the dropdown in order to indicate to the user that their choice has been selected instead of displaying the placeholder text which displays as long as value is = to an empty string.
You can pass down a state updating function as a prop to your DropDownMenu component, add this function to the same file where state has been initialized
function updateBranch(dataFromDropDownComponent) {
// modify branch data as required
// this.setState({...this.state, branchData: ... })
}
and then in JSX, pass it as a prop:
<DropDownMenu data={this.state.branchData} updateBranch={updateBranch}/>
Now in your DropDownMenu component, you can access and call the updateBranch function via this.props.updateBranch to update the state whenever required.
Related
I made a edit screen and trying to update the value of post through navigation v4 by using getParams and set setParams but when I change the old value and click save buttton to save it, it's not updating it and no error is showing either. It's still showing old values. Can someone please help me, below is my code
EditScreen.js
class EditScreen extends Component {
render() {
const { params } = this.props.navigation.state;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 100}
>
<Image
style={styles.image}
source={this.props.navigation.getParam("image")}
/>
<View style={styles.detailContainer}>
<AppTextInput
value={this.props.navigation.getParam("title")}
onChangeText={(text) =>
this.props.navigation.setParams({ title: text })
}
/>
<AppTextInput
value={this.props.navigation.getParam("des")}
onChangeText={(text) =>
this.props.navigation.setParams({ des: text })
}
/>
</View>
<AppButton
text="Save"
style={styles.button}
onPress={() => {
this.props.navigation.getParam("onEdit");
this.props.navigation.goBack();
}}
/>
</KeyboardAvoidingView>
Home.js
class Home extends Component {
state = {
modal: false,
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
],
};
onEdit = (data) => {
const newPosts = this.state.post.map((item) => {
if (item.key === data.key) return data;
else return item;
});
this.setState({ post: newPosts, editMode: false });
};
render() {
return (
<Screen style={styles.screen}>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
this.props.navigation.navigate("Edit", {
image: item.image,
title: item.title,
des: item.des,
onEdit: this.onEdit,
})
}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card onPress={() => this.props.navigation.push("Details", item)}>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<Text style={styles.title} numberOfLines={1}>
{item.title}
</Text>
<Text style={styles.subTitle} numberOfLines={2}>
{item.des}
</Text>
</View>
</Card>
</>
I recommend you to keep the data in the component state:
constructor(props) {
super(props);
// get the data that you need from navigation params
const { key, title, ..} = this.props.navigation.state.params
this.state = {key, title, ..}
}
then :
<AppTextInput
value={this.state.title}
onChangeText={(text) =>
this.setState({ title: text })
}
/>
<AppButton
text="Save"
style={styles.button}
onPress={() => {
this.props.navigation.getParam("onEdit")(this.state);
this.props.navigation.goBack();
}}
/>
Maybe try this:
<AppButton
text="Save"
style={styles.button}
onPress={() => {
this.props.navigation.getParam("onEdit")(this.props.navigation.state.params);
this.props.navigation.goBack();
}}
/>
and:
this.props.navigation.navigate("Edit", {
key: item.key,
image: item.image,
title: item.title,
des: item.des,
onEdit: this.onEdit,
})
how can I access a single element from an array nested in a state like this
state = {
modal: false,
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
]
};
.....
<MyList.Provider
value={{
}}
>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.deleteItem(item)}
style={styles.Delete}
>
<MaterialCommunityIcons name="delete" color="red" size={30} />
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.props.navigation.navigate("Edit", item)}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card
title={item.title}
subTitle={item.des}
image={item.image}
onPress={() =>
this.props.navigation.navigate("Details", item)
}
/>
</>
)}
/>
</MyList.Provider>
how can I do this like this.state.post({title}) or some way else??
I need to use this values with context so I can share and change some particular data with between 2 screens. I know to pass data I need to use context or navigation.navigate("route name",item). But if I use navigation I won't able to edit it but how can I pass data in context value from array set, if I do this.state.post it will return whole list and if i do this.state.post[0].title it will return only title of that post. So how can i do this? Please help
You have to indicate the index of the object you’re trying to access in the array. For instance to access the first object in the array you can do this
this.state.post[0]
below is my solution which follows the logic i think you are trying to achieve. I have used a flatlist
Let me know if it helps
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
FlatList,
} from 'react-native';
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
modal: false,
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
]
};
}
handleEdit(item) {
const { post } = this.state;
const extractIndex = post.findIndex(e => e.key === item.key);
const newPost = post[extractIndex];
this.props.navigation.navigate('Edit', { newPost })
this.setState({ post });
}
handleDelete(item) {
const { post } = this.state;
const newPost = post.filter(e => e.key !== item.key);
this.setState({ post: newPost });
}
renderItem = ({ item }) => {
return (
<View>
<Text>
{item.title}
</Text>
<TouchableOpacity key={item.key} onPress={this.handleEdit.bind(this, item)}>
<Text>Edit</Text>
</TouchableOpacity>
<TouchableOpacity key={item.key} onPress={this.handleDelete.bind(this, item)}>
<Text>Delete</Text>
</TouchableOpacity>
</View>
);
}
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.post}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
Use .map() function
Ex-
var cat_data = categories_list.map(function (item) {
var cat_data = categories_list.map(function (item) {
return {
name: item.Name,
thumb_url: item.PictureModel.ImageUrl,
cat_id: item.Id.toString(),
};
});
this.setState({
data: cat_data,
});
i wanna implement a page able to list some categories and once clicked, do some other tasks.
I've tried to implement it like I'm doing here but when I render the page, category is automatic chosen and it is set to last value.
What i wrong?
Here my code
const data = [
{category: 'a'},
{category: 'b'},
{category: 'c'},
];
<FlatList
data={data}
renderItem={({item}) => (
<View style={categoryStyles.itemContainer}>
<TouchableHighlight style={{ }} selectedCategory={item.category}
onPress={this._nextStep(item.category)}>
<View style={{alignItems:'center', justifyContent: 'space-around',}}>
<Icon name={item.icon} size={40}/>
<Text style={categoryStyles.item}>{item.description}</Text>
</View>
</TouchableHighlight>
</View>
)}
keyExtractor={item => item.id}
numColumns={numColumns} />
_nextStep = (selectedCategory) => {
if (this.state.index !== this.props.children.length - 1) {
this.setState(prevState => ({
index: prevState.index + 1,
}));
this.setState(() => ({
selectedCategory: selectedCategory,
}));
}
};
You just need to change this
onPress={this._nextStep(item.category)}
To
onPress={()=> this._nextStep(item.category)}
Here there are two tabs invoice_specific and as_hoc and one button where I am displaying sum(this.state.sum) value .
by default when I open the screen in sum state "invoice_specific" value should come I have written this in render function below .
Now if I change the tabs I am calling function handleChangeTab() ,here on tab change I have to update the state sum .
If I am in first tab invoice_specific value should display else I am in as_hoc tab them this value should assign in sum .
constructor() {
this.state = {
sum: 0,
invoice_specific: 0,
as_hoc: 0
}
this.handleChangeTab = this.handleChangeTab.bind(this)
}
handleChangeTab=(obj) =>{
console.log({ obj })
}
console value of obj in function handleChangeTab()
{ i: 1, ref: {…}, from: 0 }
from: 0
i: 1
ref: $$typeof: Symbol(react.element)
key: ".1"
props:
children: {
$$typeof: Symbol(react.element),
type: ƒ,
key: null,
ref: null,
props: {…},
…
}
heading: "AD-HOC"
tabLabel: "AD-HOC"
virtual: undefined
return function
render(){
const viewStyle = {flexDirection: 'column', padding:10, backgroundColor: '#fff', minHeight:deviceHeight }
return(
<Tabs onChangeTab={(obj)=> this.handleChangeTab(obj)}>
<Tab heading="INVOICE SPECIFIC" tabLabel="SPECIFIC">
<View style={viewStyle}>
<RegularText text="Enter Specific Amount to pay" style={{paddingBottom:5}} textColor="#959595" />
<View>
<Item style={{borderColor: '#00fff', borderBottomWidth:1}}>
<Input autoFocus={true}
onPress={()=> this.handleChange('sumValue')}
onChangeText={(sumValue) => this.handleChangeSum(sumValue)} />
</Item>
</View>
</View>
</Tab>
<Tab heading="AD-HOC" tabLabel="AD-HOC">
<View style={viewStyle}>
<RegularText text="Enter Specific Amount to pay" style={{paddingBottom:5}} textColor="#959595" />
<View>
<Item style={{borderColor: '#00fff', borderBottomWidth:1}}>
<Input autoFocus={true}
onPress={()=> this.handleChange('sumValue')}
onChangeText={(sumValue) => this.handleChangeSum(sumValue)} />
</Item>
</View>
</View>
</Tab>
</Tabs>
)
}
I didn't see that you have called setState() anywhere. You need to call setState appropriately while avoiding infinite re-rendering. Also if you can go further and change it to a functional component where you would find ref and useEffect make the code much more simpler and readable.
I am using react-native-sectioned-multi-select library. I want to open another modal view after I click the confirm button.
I feel like I did the code correctly but this isn't working. Is it possible to open a new modal inside this library?
const items = [
{
name: "Fruits",
id: 0,
children: [{
name: "Apple",
id: 10,
},{
name: "Strawberry",
id: 17,
},{
name: "Pineapple",
id: 13,
},{
name: "Banana",
id: 14,
},{
name: "Watermelon",
id: 15,
},{
name: "Kiwi fruit",
id: 16,
}]
}]
export default class TestScreen extends Component {
constructor(){
super()
this.state = {
selectedItems: [],
modalVisible: false,
}
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
onSelectedItemsChange = (selectedItems) => {
this.setState({ selectedItems });
console.log(selectedItems)
}
openModal = () => {
return(
<SafeAreaView style={{flex:1}}>
<View style={{width:300, height:400, backgroundColor:'red'}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{marginTop: 22}}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
<TouchableHighlight
onPress={() => {
this.setModalVisible(true);
}}>
<Text>Show Modal</Text>
</TouchableHighlight>
</View>
</SafeAreaView>
)
}
render() {
return (
<SafeAreaView style={{flex:1}}>
<View>
<SectionedMultiSelect
items={items}
uniqueKey='id'
subKey='children'
selectText='Choose some things...'
showDropDowns={true}
readOnlyHeadings={true}
onSelectedItemsChange={this.onSelectedItemsChange}
selectedItems={this.state.selectedItems}
//Here I call the openModal function but nothing appears
onConfirm={()=> {this.openModal}}
/>
</View>
</SafeAreaView>
);
}
}
Any comments or advise would be really appreciated! Thanks in advance! :)
Edited
If I can't open two modals at a time, I want my new modal to open after I close my first modal.
Multiple simultaneously open modals do not work in React Native. You could:
close the first modal before opening the second one, then reopening the first one when you're done with the second
roll your own modal using 'position: absolute' styling
Firstly, make sure both the Modal's aren't using the same state values for the visible prop in Modal.
You can use visible prop as visible={this.state.modalPage1}. The state modalPage1 should be initiated to bool value.
So if the scenario is that you are closing the first Modal and opening another one, then
this.setState({
modalPage1: false,
modalPage2: true
});
Hope I could help you. Do comment if any other Doubts.
You could manipulate multiple modal visibility with Conditional Rendering using logical operator. Here is the snippet code that might work in your case:
{
this.state.isFirstModalOpen && (
<Modal
animationType="slide"
transparent={false}
visible={this.state.isModalOpen}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}
>
<View style={{ marginTop: 22 }}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
this.setState({
isFirstModalOpen: false,
isSecondModalOpen: true
});
}}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
);
}
{
this.state.isSecondModalOpen && (
<Modal
animationType="slide"
transparent={false}
visible={this.state.isSecondModalOpen}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}
>
<View style={{ marginTop: 22 }}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
this.setState({ isSecondModalOpen: false });
}}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
);
}
render() {
return (
<SafeAreaView style={{flex:1}}>
<View>
<SectionedMultiSelect
items={items}
uniqueKey='id'
subKey='children'
selectText='Choose some things...'
showDropDowns={true}
readOnlyHeadings={true}
onSelectedItemsChange={this.onSelectedItemsChange}
selectedItems={this.state.selectedItems}
//Here I call the openModal function but nothing appears
//onConfirm={()=> {this.openModal}} <-- change this with
onConfirm={() => this.setState({modalVisible: true})}
/>
</View>
</SafeAreaView>
);
}
You dont call directly a modal, you have to toggle the visible state of modal
And then you need to close the modal as well whenever your task is completed, all you need to do is, on click or on Press....
this.setState({ modalVisible: false });