Multiple item data. Show the data as clicked in the dynamically modal with react-native - react-native

FOOD> PIZZA> clicking on any pizza opens a modal. I want to show the information of the pizza clicked in this modal. I looked at many similar examples but I could not get out of it. So I need help. I add some parts of the code below. At the same time, the code is available in the expo and the link below
snack.expo.io/#ibrahimyolbir/e48b05
accordion
<Accordion
dataArray={this.state.menus}
animation={true}
expanded={true}
renderHeader={this._renderHeader}
renderContent={this._renderContent}
/>
my open modal button in the render content
onPress={this.triggerModal(food)}
_renderContent = (item) => {
return (
<List>
{
item.food.map((food, index) => {
return (
<ListItem style={{
backgroundColor: "#f0f0f5",
padding: 10,
marginLeft: 0,
paddingRight: 10,
fontStyle: "italic",
listStyleType: "none",
flexDirection: "row",
justifyContent: "space-between"
}}>
<TouchableOpacity
onPress={this.triggerModal(food)}
style={{
flexDirection: "row",
justifyContent: "space-between"
}}
>
<Left style={{
maxWidth: 57
}}>
<Thumbnail source={require("../assets/images/left-food-icon.png")} />
</Left>
<Body>
<Text >{food.name}</Text>
<Text note >{food.description}</Text>
</Body>
<Right>
<Text >{food.price} :-</Text>
</Right>
</TouchableOpacity>
</ListItem>
)
}
)
}
</List>
);
}
MODAL
<Modal
style={{ marginTop: 122 }}
isVisible={this.state.display}
visible={this.state.display}
onSwipeComplete={() => this.setState({ isVisible: false })}
onSwipeThreshold={1}
swipeDirection="down"
animationType="slide"
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{ flex: 1, backgroundColor: "#fff" }}>
<Text>Hello!</Text>
<TouchableOpacity onPress={this.closeDisplay} style={{ marginTop: 40, marginLeft: 150 }}>
<Text> CLOSE MODAL </Text>
</TouchableOpacity>
{/* <Text> {this.state.menus} </Text> */}
</View>
</Modal>

One of the way can be:
1)Create a new state
currentChildData:[],
currentParentData:[],
2)Pass parent id and child index in onPress event
<TouchableOpacity onPress={()=>this.triggerModal(item.id,index)}
3)Using that passed index and parent id,we can extract relevant information about(to be clicked item) from menus state
triggerModal = (ParentIndex,childIndex) => {
this.setState(prevState => {
let ParentData=[...prevState.menus].find(each=>each.id==ParentIndex)
return {
display: true,
currentChildData: ParentData.food[childIndex],
currentParentData: ParentData,
}
});
}
4)Now we have information of(to be clicked item) in our state. We then can use it like (name of item shown below) inside Modal
<Text>{this.state.currentChildData.name}</Text>
Working Code: https://snack.expo.io/By_QVbPMI

U missed the key from mapped array in a ListItem component. Add it as a prop key={Index} .
Also U need item from map as argument in ur onPress, cuz u need to push visited/selected elements to the state. {()=>this.openModal(itemFromMap)}
And then u can manipulate with data like u need.
As I can understood u have array of objects. Object.keys(itemFromMap).map(...
And return data to the needed part of ur modalInnerContainer.

Related

1st index hidden Item not hidding when swiping the another element - swiperFlatList React native

as you can see in the image, I have implemented adding Text inputs dynamically with the button press, everything is working perfectly only the 1st text input hidden item (Remove Button) not hiding when swiping the other text inputs.
const initialState = {
col1: '',
key: 0,
};
const [inputField, setInputField] = useState<Values[]>([initialState]);
<SwipeListView
data={inputField}
renderItem={data => renderItem(data)}
renderHiddenItem={data => renderHiddenItem(data)}
leftOpenValue={55}
rightOpenValue={-100}
disableRightSwipe={true}
ListHeaderComponent={
<View style={[styles.headingContainer]}>
<Text style={[styles.headingText]}>{Props.inputHeading}</Text>
</View>
}
ListFooterComponent={
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.addBtn}
activeOpacity={0.7}
onPress={onPressAddBtn}>
<Text style={styles.BtnText}>Add</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.submitBtn} activeOpacity={0.7}>
<Text style={styles.BtnText}>Submit</Text>
</TouchableOpacity>
</View>
}
style={{height: Dimensions.get('screen').height / 1.3}}
/>
const renderItem = (data: any) => {
return (
<TouchableHighlight key={data.item.key}>
<TextInput
placeholder="Hello"
onChangeText={e => handleChange(data.item.key, 'col1', e)}
value={data.item.col1}
style={[styles.textInput, Props.textInputStyle]}
// {...Props.textInputProps}
/>
</TouchableHighlight>
);
};
const renderHiddenItem = (rowData: any) => {
return (
<View
style={{
justifyContent: 'flex-end',
flexDirection: 'row',
alignItems: 'center',
}}>
<TouchableOpacity
activeOpacity={0.7}
style={{
backgroundColor: 'red',
justifyContent: 'center',
flexDirection: 'row',
width: 90,
height: 45,
alignItems: 'center',
borderRadius: 5,
}}>
<Text style={{color: 'white'}}>Remove</Text>
</TouchableOpacity>
</View>
);
};
but other all element's swipe is working as expected only the first element is not working as expected
found solution by adding keyExtractor={item => item.key.toString()} to swiper flatlist.

Align all icon to the right of page regardless of start point React Native

I want to be able to align all reply icons to the far right, where the red line is, regardless of where they start.
Edit: added more information to show how recursion is used in the component. Why I try to use some answers that work without recursion, I receive an undesired effect.
This is the code I have in place so far:
class Comment extends Component {
render() {
return(
<View>
<Header
rounded
style={{
backgroundColor: '#ffffff',
position: 'relative',
}}
>
<View style={{flexDirection: 'row', flexWrap: 'wrap', right: '43%', top: '50%'}}>
<Icon name='chevron-left' size={10} color='#006FFF' style={{top: '6%'}}/>
<NativeText
onPress={() => this.props.history.push('/')}
style ={{color: '#006FFF', fontSize: 12, fontFamily: 'Montserrat-Regular'}}
>
Back
</NativeText>
</View>
</Header>
<View
style={{paddingLeft: '2%', paddingTop: '2%'}}
>
<CommentList
options={this.props.location.state.comments}
currentUser={this.props.location.state.currentUser}
history={this.props.history}
reportId={this.props.location.state.reportId}
optionsForBackButton={this.props.location.state.comments}
/>
</View>
</View>
)
}
}
export default withRouter(Comment)
const CommentList = ({options, currentUser, history, reportId, optionsForBackButton}) => {
return (
<View>
{options.map(option => (
<View
style={{flexDirection: 'row'}}
>
<NativeText
style={{fontSize: 12, fontFamily: 'Montserrat-Regular'}}
>
{option.content}
</NativeText>
<View
style={{flex: 1, alignItems: 'flex-end' }}
>
<Icon
name='reply'
size={12}
// onPress={() => {
// setModalVisible(true)
// changeParentId(option._id)
// }}
onPress={() => history.push({pathname: '/create-comment', state: {content: option.content, currentUser: currentUser, reportId: reportId, parentCommentId: option._id, optionsForBackButton: optionsForBackButton}})}
/>
</View>
{
<View
style={{left: '10%'}}
>
<CommentList
options={option.reply}
optionsForBackButton={optionsForBackButton}
history={history}
currentUser={currentUser}
reportId={reportId}
/>
</View>
}
</View>
))}
</View>
)
}
Set your icon containing view's flex value to 1. This should cause it to fill all remaining space.
See the following snack: https://snack.expo.io/#jrdndncn/playful-churros
class Comment extends React.Component {
render() {
return (
<View
style={{
marginVertical: 2,
flexDirection: 'row',
marginLeft: (this.props.indent || 0) * 20,
}}>
<Text>{this.props.text}</Text>
<View style={{ flex: 1, alignItems: 'flex-end' }}>
<View style={{ width: 20, height: 20, backgroundColor: 'red' }} />
</View>
</View>
);
}
}
<Comment text="hello" indent={0} />
<Comment text="hello" indent={1} />
<Comment text="hello" indent={2} />
Basically marginLeft:'auto' will do the trick. just add style to icon as :
<Icon
name='reply'
size={12}
style={{marginLeft:'auto'}}
// onPress={() => {
// setModalVisible(true)
// changeParentId(option._id)
// }}
onPress={() => history.push({pathname: '/create-comment', state: {content: option.content, currentUser: currentUser, reportId: reportId, parentCommentId: option._id, optionsForBackButton: optionsForBackButton}})}
/>
i added marginLeft:'auto' in style it will automatically shown at the right end of the screen.

Is it possible to use searchableDropdown inside a Modal (react-native)?

I am trying to use Searchable Dropdown inside a modal in react native.If i use it 'alone' (i mean outside the modal) it works fine.But if i put it inside a modal , its attribute onItemSelect does not seem to work( it does not let me click on anything)
<Modal isVisible={this.state.isBuildingModalVisible}>
<SearchableDropdown
onItemSelect={item => {
this.setState({ building_id: item.id });
}}
containerStyle={{ ...}}
textInputStyle={{
...
}}
itemStyle={{
...
}}
itemTextStyle={{
color: "white",
fontSize: (15 / 411.42) * screen
}}
itemsContainerStyle={{ maxHeight: 140 }}
items={this.state.dataSource}
placeholder="Choose School"
placeholderTextColor="white"
underlineColorAndroid="transparent"
/>
<View
style={{
alignItems: "center",
justifyContent: "center",
flexDirection: "row"
}}
>
<TouchableOpacity
style={styles.button}
onPress={this.toggleBuildingModal}
>
<Text style={{ color: "white" }}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => this.submitpassword()}
>
<Text style={{ color: "white" }}>Execute</Text>
</TouchableOpacity>
</View>
</Modal>
Ok the problem was that react native does not allow you to put SearchableDropdown inside scrollview (if anyone has this problem :P)

How to use checkboxes in react native for both android and IOS?

I have a modal with diffrent tabs in my app in which user can filter the search result with categories in the modal . right now it is working but I simply put an event on a <TEXT> , I need some visual clue like checkbox for my options
{this.state.currentTab === 1 && (
<View>
<Text onPress={(text) => this.setGender(true)}>male</Text>
<Text onPress={(text) => this.setGender(false)}>female</Text>
</View>
)}
How Can I use checkbox instead of <TEXT> to use both in android and IOS?
You can use this library for the checkbox
" react-native-circle-checkbox "
import CircleCheckBox, {LABEL_POSITION} from 'react-native-circle-checkbox';
{this.state.currentTab === 1 && (
<View>
<CircleCheckBox
checked={true}
onToggle={(text) => this.setGender(true)}
labelPosition={LABEL_POSITION.RIGHT}
label="MALE"
/>
<CircleCheckBox
checked={true}
onToggle={(text) => this.setGender(false)}
labelPosition={LABEL_POSITION.RIGHT}
label="FEMALE"
/>
</View>
)}
Example: https://snack.expo.io/#msbot01/intrigued-marshmallows
Use This Component which I manually created. It renders same radio button on both platforms
const RenderRadio = (props) => {
const {
value, onChange, selectedValue
} = props;
const checked = value === selectedValue;
return (
<TouchableOpacity
style={{ flexDirection: 'row' }}
onPress={() => onChange(value)}
>
<View
style={{
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
borderColor: '#002451',
justifyContent: 'center',
alignItems: 'center',
}}
>
<View
style={{
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: checked ? '#002451' : 'white',
}}
/>
</View>
<Text style={{ fontSize: 15, marginLeft: 10 }}>{value}</Text>
</TouchableOpacity>
);
};
use it as
<RenderRadio onChange={this.setSelectedValue} selectedValue={selectedValue} value={value}/>
and set Your selected value as
setSelectedValue = (value) => {
this.setState(selectedValue : value)
}
You can use native-base library, that has more components which you can use for Search filters and this is more reliable, you can set it checked
using checked prop, that is boolean, like this :
import {
Icon,
CheckBox,
Spinner
} from "native-base";
<TouchableOpacity onPress={(text) => this.setGender(true)} >
<CheckBox checked ={tru}
onPress={(text) => this.setGender(true)} />
</TouchableOpacity>

StackNavigator this.props.navigation cached

I am using a FlatList and within it I am doing:
let pressed = () => {
this.props.navigation.navigate('DetailScreen', {item: item});
}
then in render() on the DetailScreen I am doing: this.props.navigation.getParam('item', null)
so the first item I click on in the list, shows the correct item in the DetailScreen, but then if I go back and click on any other item then this.props.navigation.getParam('item', null) always returns the same item. Its like it does not get changed after the first select.
List.js
_renderRow({item}){
let pressed = () => {
this.props.navigation.navigate('Details', {item: item});
}
let actualRowComponent =
<View style={css.list.row}>
<View style={css.list.rowContainer}>
<Text style={css.list.rowSymbol}>{item.sym}</Text>
<Text style={css.list.rowTitle}>{item.title}</Text>
</View>
<Button title={"$"+item.amount}
onPress={pressed}
backgroundColor='#EE7600'
buttonStyle={{borderRadius: 5}}
/>
</View>;
let touchableWrapperIos =
<TouchableHighlight
activeOpacity={0.5}
underlayColor="#fff"
onPress={pressed}
>
{actualRowComponent}
</TouchableHighlight>;
let touchableWrapperAndroid =
<TouchableNativeFeedback
useForeground={true}
background={TouchableNativeFeedback.SelectableBackgroundBorderless()}
onPress={pressed}
>
{actualRowComponent}
</TouchableNativeFeedback>;
if (require('react-native').Platform.OS === 'ios') {
return touchableWrapperIos;
}
else return touchableWrapperAndroid;
}
render(){
return (
<View style={css.baseStyles.baseContainer}>
<View style={{justifyContent: 'center',alignItems: 'center', marginBottom: 40, marginTop: 50}}>
</View>
<SectionWidget title="Items" >
<FlatList
style={css.baseStyles.flatListContainer}
data={this.items}
renderItem={this._renderRow}
keyExtractor={(item,index) => item.id.toString()}
/>
</SectionWidget>
</View>
);
}
Detail.js
render(){
const item = this.props.navigation.getParam('item', null);
console.log(item.title)
return (
<View style={css.baseStyles.container}>
<ScrollView>
<View style={{marginTop: 40, marginBottom: 60, flex: 1, justifyContent: 'center',alignItems: 'center'}}>
<Text style={css.baseStyles.priceText}>${item.amount}</Text>
<Text style={css.baseStyles.subText}> +$0.50 </Text>
</View>
<Divider style={{ backgroundColor: '#ccc', marginLeft: 10, marginRight: 10 }} />
<View style={{marginTop: 60, marginBottom: 30, flex: 1, justifyContent: 'center',alignItems: 'center'}}>
<Text style={css.baseStyles.titleText}>{item.title}</Text>
<Text style={css.baseStyles.descriptionText}>{item.summary}</Text>
</View>
<Divider style={{ backgroundColor: '#ccc', marginLeft: 10, marginRight: 10 }} />
</ScrollView>
<View style={css.baseStyles.footerContainer}>
<Button title='Buy'
backgroundColor='#EE7600'
buttonStyle={{marginTop: 20, marginBottom: 20, borderRadius: 5, width: 150}}
/>
</View>
</View>
);
}
Since I've never used React Navigation before, I was misunderstanding its usage. In fact your problem seems a logic/usage one, which has a simple solution. Your intention is to have multiple Detail screen (I mean just a component, but multiple screen in the stack), not just one with different params. This makes a BIG difference! React Navigation provides an alternative method to navigation.navigate(), which is navigation.push(), that adds a stack to the 'history' of navigation and seems to be exactly what you're looking for.
So, what you have to do is to replace
this.props.navigation.navigate('Details', {item: item});
with
this.props.navigation.push('Details', {item: item});
You can read more (and better explained) about this on the official doc.
Let me know if this fits with your problem.
The issue I found was due to #autobind. If you use #autobind along with react-navigation, you will run into problems. So I removed #autobind and everything is working as expected.