Can't pass details from FlatList items to Modal - javascript

I have FlatList and I want to open each FlatList Item in Modal to see details. In this example I am trying to click on {rowData.data.display_name} to see {rowData.data.display_name} inside of Modal. I get data from API and when I open Modal it's not the same item that I clicked on. I am not sure how would I set up item id to see the same item inside of Modal? Any help would be appreciated!
Here is my code:
<FlatList
data={this.state._data}
renderItem={({item: rowData}) => {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={this.openModal}>
<Text style={styles.title}>
{rowData.data.display_name}
</Text>
</TouchableOpacity>
<Modal
style={styles.modal}
ref={(modal) => this.modal = modal}
coverScreen={true}
swipeToClose={this.state.swipeToClose}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>
{rowData.data.display_name}
</Text>
</Modal>
</View>
);
}}
keyExtractor={(item, index) => index}
/>

In my opinion you should put the Modal outside the FlatList. The way you codded it you're overwritting the "this.modal" every time a new Item from the list is created.
Then you would just accept changing the text of the Modal (probably via state) on your openModal function inside the Modal component, and on your renderItem, change the onPress to pass the infos from the container you want the modal to show.
onPress={()=> this.openModal(rowData.data)}>

Related

How to check if press outside a component in react-native?

I did a custom select but I have the problem to close it if I press outside the select or options. basically the "button" is a TouchableOpacity and when I click on it there appears the list of options. But now I can close it only by choosing one option or clicking back on the select button. Is there a way to check whether I click outside the TouchableOpacity or not? In simple react you can give an Id to the component and check it onClick event to see what you have clicked. Or you can use react's useRef hook which doesn't seem to work with react-native. I have this code (simplified):
const [isOpen, setIsOpen] = useState(false)
const toggle = () => { setIsOpen(!isOpen)}
//...
return (<View>
<TouchableOpacity onPress={toggle}>
<Text>Open select</Text>
</TouchableOpacity>
<View>
{isOpen && options.map(({value, label}) => <View key={value} onPress={toggle}>{label}</View>)}
</View>
</View>)
As you can see you can call toggle only if you press the select button or an option. I want to call setIsOpen(false) when I click outside the TouchableOpacity box.
Is there a way or library to do it?
First of all correct usage for toggle function is
setIsOpen(prevIsOpen => !prevIsOpen);
And regarding your question. Just wrap all screen into touchable component without any feedback.
const close = () => isOpen && setIsOpen(false);
return (
<TouchableWithoutFeedback onPress={close} style={{ flex: 1 }}>
<View>
<TouchableOpacity onPress={toggle}>
<Text>Open select</Text>
</TouchableOpacity>
<View>
{isOpen && options.map(({value, label}) => <View key={value} onPress={toggle}>{label}</View>)}
</View>
</View>
</TouchableWithoutFeedback>
);
you can use TouchableWithoutFeedback

How can I set focus on the first TouchableHighlight component (or another one, given by ref for instance) inside the modal when modal is opened?

How can I set focus to the first (or any given) TouchableHighlight component inside the modal when it's opened?
I'm using D-pad/kayboard/TV Remote
Let's use the fragment of the react-native documentation modal example:
<View style={{marginTop: 22}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{marginTop: 22}}>
<View>
<TouchableHighlight>
<Text>Button 1</Text>
</TouchableHighlight>
<TouchableHighlight>
<Text>Button 2</Text>
</TouchableHighlight>
<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>
Navigation with D-pad works, but when the modal is opened, the first TouchableHighlight (button 1) is not focused, focus remains on the "Show Modal" button
Or, How can I set focus on the "Button 2" TouchableHighlight programatically?
TextInput for example has autoFocus, but TouchableHighlight no, if we are using only Touchable components inside a modal, I don;t know how to autoFocus them, or set implicitely it
Best Regards
Add hasTVPreferredFocus: true to the TouchableHighlight you want focused.
It is implemented on Android even though the documentation states that hasTVPreferredFocus is iOS-only.
Programmatically you can also force the focus by calling:
yourElementRef.setNativeProps({ hasTVPreferredFocus: true })
#mtkopone . is there any way to focus View component, i have a list which is inside View and i want to do some function calls when user focus on that View (onFocus,onBlur)
initialRef.current.setNativeProps({hasTVPreferredFocus: true});

React native open modal into a modal

How to open modal from the modal box in react native.
ex: I have one form in modal and one color picker field into the form so how can I open color picker to another modal.
Name: XYZ
Age: 21
Color: A (This is the color picker. When I click the text open color picker in modal)
Render the nested color modal inside the outer modal as content, the visibility of nested modal will depend on the click/press over the text. Consider the sample code below, for demonstration purpose, I have used react-native-color-picker library, you can use any other library as well.
Sample
Initializing state variable, outerModalVisible controls the visibility of outer modal and nestedModalVisible controls the visibility of nested modal. In the sample code, outerModalVisible value remain true but you can change it as per your requirement.
state={
outerModalVisible: true,
nestedModalVisible: false,
selected_color: '#fff'
}
In render method, defining the outer model and nested modal
<View>
<Modal visible={this.state.outerModalVisible} >
<View style={styles.container}>
<Text>Name: XYZ</Text>
<Text>Age: 21</Text>
<TouchableOpacity onPress={() =>{
this.setState({
nestedModalVisible: true
});
}}>
<Text>Color picker: {this.state.selected_color}</Text>
</TouchableOpacity>
<Modal
visible={this.state.nestedModalVisible}
>
<View style={styles.container}>
<ColorPicker
onColorSelected={color => {
this.setState({
selected_color: color,
nestedModalVisible: false
});
}}
style={{flex: 1}}
/>
<Button title="click to close" onPress={() =>{
this.setState({
nestedModalVisible: false
});
}} />
</View>
</Modal>
</View>
</Modal>
</View>
You may define the content of nested model in a separate component, I just keep it simple and defined it inside a single component.
Hope this will help!

Detox - Testing visibility of modal in react native

We are using detox to write E2E testing of a react native app where we have a case which needs to test if a modal appears after a button tap.
But detox was not able to identify modal with the given testID thought the modal opens as expected. Is there a different way test modal in reactnative using detox?
Below is the modal JSX
<Modal
testID="loadingModal"
animationType="none"
transparent
visible={loading}
onRequestClose={() => {}}
>
<View style={styles.modalContainer}>
<View style={styles.loginModal}>
<ActivityIndicator
animating
size="large"
color="#00e0ff"
/>
<Text style={styles.login}>Logging in...</Text>
</View>
</View>
</Modal>
And below is the code to test the visibility of modal
it('should have welcome screen', async () => {
....
await element(by.text('CONTINUE')).tap();
await waitFor(element(by.id('loadingModal'))).toBeVisible().withTimeout(5000);
await expect(element(by.id('loadingModal'))).toBeVisible(); // this always fails
});
React Native's Modal component creates a view controller which manages the rendering of child views on the native level. Unfortunately, it doesn't pass down testID, so the best way I've found is to wrap the contents of the modal in a <View>, and pass the testID prop to that component. In your case, you could do:
<Modal
animationType="none"
transparent
visible={loading}
onRequestClose={() => {}}
>
<View
style={styles.modalContainer}
testID="loadingModal" // Just move the testID to this element
>
<View style={styles.loginModal}>
<ActivityIndicator
animating
size="large"
color="#00e0ff"
/>
<Text style={styles.login}>Logging in...</Text>
</View>
</View>

In React Native, is it possible to call onPress while keyboard open [duplicate]

This question already has an answer here:
React Native - Select row on ListView when keyboard is open
(1 answer)
Closed 4 years ago.
The user needs to click twice on the FlatList item because autoFocus={true} for the <TextInput. At the first click the keyboard is hiding and next click calling onPress={this.GetItem.bind(this, item)}. Is there any option to call GetItem() on the first click instead of clicking twice.
Demo: https://snack.expo.io/ByJ_yWehM
export default class App extends Component {
GetItem (item) {
console.log(item);
Alert.alert(item);
}
render() {
return (
<View style={styles.container}>
<TextInput
autoFocus={true}
style={styles.paragraph}
keyboardType='web-search'
>
Change code in the editor and watch it change on your phone!
Save to get a shareable url.
</TextInput>
<Card title="Local Modules">
<View>
<TextInput
style={styles.searchField}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({text})}
/>
<FlatList
data={["akin","alike","close","comparable","like","similar","uniform","Allied","Analogous","Co-ordinate","Commensurate","akin","alike","close","comparable","like","similar","uniform","Allied","Analogous","Co-ordinate","Commensurate"]}
renderItem={({item}) => (
<Text
style={styles.listField}
onPress={this.GetItem.bind(this, item)}
>{item}</Text>
)}
/>
</View>
</Card>
</View>
);
}
}
The purpose of the component is giving autosuggestion in <FlatList> when user searching in <TextInput>
Adding keyboardShouldPersistTaps='handled' to your FlatList will prevent keyboard from being dismissed onPress.
<FlatList
keyboardShouldPersistTaps='handled'
data={["akin","alike","close","comparable","like","similar","uniform","Allied","Analogous","Co-ordinate","Commensurate","akin","alike","close","comparable","like","similar","uniform","Allied","Analogous","Co-ordinate","Commensurate"]}
renderItem={({item}) => (
<Text
onPress={this.GetItem.bind(this, item)}
>{item}</Text>
)}
/>
always also works as keyboardShouldPersistTaps value.
Official doc for keyboardShouldPersistTaps here

Categories