React Native : Modal closing functionality - react-native

I am currently following the modal example given here.
https://facebook.github.io/react-native/docs/modal.html
The code works and it is indeed showing a modal box.
But there is no "close" functionality except the one via TouchableHighlight onPress event.
Is it possible to have a "close modal" functionality via "X" on the corner ?
I checked out the props and I am not able to find any.
So does this mean that using only the TouchableHighlight's onPress event alone you will be able to control the modal's closing ?
App.js code
import React, { Component } from 'react';
import { Modal, Text, TouchableHighlight, View } from 'react-native';
export default class ModalExample extends Component {
state = {
modalVisible: false,
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={{marginTop: 22}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {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>
);
}
}

import React, { Component } from 'react';
import { Modal, Text, TouchableHighlight, View } from 'react-native';
export default class ModalExample extends Component {
state = {
modalVisible: false,
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
closeModal = () => {
this.setState({modalVisible: false})
}
render() {
return (
<View style={{marginTop: 22}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {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>
<CloseButton onPress={this.closeModal} /> // Create your 'X' button with your preferred styling
</View>
</Modal>
<TouchableHighlight onPress={() => {
this.setModalVisible(true)
}}>
<Text>Show Modal</Text>
</TouchableHighlight>
</View>
);
}
}
You just need to add a button to the modal with your preferred styling and on the button's onPress listener set the state variable modalVisible to false for hiding the modal.

Related

Modal open and close not working properly

I have added the below reusable code to show Modal and close the Modal when clicked outside of that Modal, when I click on a button the Modal is shown and when I click outside of that Modal it gets closed till here it is working properly but again when I click on a button to open Modal, the Modal is not shown, and I can't use props on can anyone tell me any other solution and what mistake I have made in the below code.
import React, { FunctionComponent, useState } from 'react';
import { Modal, FlatList,TouchableWithoutFeedback } from 'react-native';
interface Props {
visible: boolean;
onClose: () => void;
}
const BottomSheet: FunctionComponent<Props> = (props) => {
const [showBottomSheet,setBottomSheet]=useState(true);
if(showBottomSheet){
return (
<Modal animationType={ANIMATIONS.SlideType} transparent={true} visible={props.visible}>
<TouchableWithoutFeedback onPress={()=> setBottomSheet(false)}>
<View style={Styles.opacityContainer}></View>
</TouchableWithoutFeedback>
<View style={Styles.container}>
<View style={Styles.headerContainer}>
<View style={[Styles.header, Styles.directionRow]}>
<View>
<Text style={Styles.headerText}>Add</Text>
</View>
<View style={Styles.iconContainer}>
<Icon
name={cancel}
size={18}
IconClick={props.onClose}
/>
</View>
</View>
</View>
<View style={Styles.viewContainer}>
<SafeAreaView>
<FlatList
horizontal={false}
data={props.navData}
renderItem={renderActions}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
</View>
</View>
</Modal>
);
}
return null;
};
This is the other file where I am using the above reusable component
customer.tsx
const [showBottomSheet, setShowBottomSheet] = useState(false);
const hideBottomSheet = () => {
setShowBottomSheet(false);
};
<View style={Styles.profileContainer}>
<AddButton
onButtonPress={() => {
setShowBottomSheet(true);
}}
iconObject={{
iconName: plus,
iconSize: Sizes.plusLargeSize,
}}
/>
<BottomSheet
visible={showBottomSheet}
onClose={hideBottomSheet}
/>
</View>

I can't trigger the modal component to open from a different component

I declared a Modal component in a separate js file and I'm trying to make it appear when an onPress event happens. I can't seem to be able to toggle that.
I Googled and found React Native open modal from different component but either I'm not getting something or that doesn't work for me.
I have the following modal.js:
import React, {Component} from 'react';
import {
Modal,
StyleSheet,
Text,
TouchableHighlight,
View,
Alert
} from 'react-native';
import config from '../config/colors';
export default class ModalWindow extends Component {
state = {
modalVisible: false,
};
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={styles.container}>
<Modal
animationType="fade"
transparent={false}
visible={this.state.modalVisible}
onDismiss={() => {
console.log('Modal has been closed.');
}}>
<View style={styles.container}>
<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>
);
}
}
const styles = StyleSheet.create({
container: {
position: 'absolute',
marginTop: 22
}
});
And inside a separate file I have:
import Modal from '../components/modal';
and declared the component inside my render as such
... other stuff ...
<View style={styles.modalContainer}>
<Modal isModalVisible={this.state.modalVisible}></Modal>
</View>
... other stuff ...
finally, I have a button set such that this gets called: onPressAvatar={this.onPressAvatar}
and that method is:
onPressAvatar = props => {
console.log("press avatar");
this.setState({modalVisible: true});
}
I know the onPress works because the console.log() gets triggered but the modal doesn't appear. What am I missing?
You need to use props to open/close your modal like this:
import React, {Component} from 'react';
import {
Modal,
StyleSheet,
Text,
TouchableHighlight,
View,
Alert
} from 'react-native';
import config from '../config/colors';
export default class ModalWindow extends Component {
render() {
return (
<View style={styles.container}>
<Modal
animationType="fade"
transparent={false}
visible={this.props.isModalVisible}
onDismiss={() => {
console.log('Modal has been closed.');
}}>
<View style={styles.container}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
this.props.close();
}}>
<Text>Hide Modal!</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
<TouchableHighlight
onPress={() => {
this.setModalVisible(true);
}}>
<Text>Show Modal</Text>
</TouchableHighlight>
</View>
);
}
}
Note that I change this.state.modalVisible to this.props.modalVisible and I remove the methods that set the states
Here you pass your state values
... other stuff ...
<View style={styles.modalContainer}>
<Modal isModalVisible={this.state.modalVisible} close={this.setState({modalVisible: false})}></Modal>
</View>
... other stuff ...
And now your component is controlled by your Parent component that changes its own state and propagate to your Modal.
A component has props and states, props are immutable objects that the component receives when you pass data by setting attributes like <Modal isModalVisible={value} />. They become available to your component by the property this.props. On the other hand the State property is used to control the internal state of the component and each state change using this.setState causes a new rendering call. So in your code we need to set Parent component State to notify all the components children that there are changes. Then your Modal component will call its own method render to show or hidden the modal box.

How to create a separate class for a component in react native and use it as a common class?

Hi I am learning react native. I am using Modal component of react native. I need to use the same across multiple times in app. Here the code
Now I am trying to call the function
{this.createModal(dataForMaritalStatus)}
instead of
/* <Modal visible={this.state.isModalVisible}
onRequestClose={() => {
this.setState({ isModalVisible: false })
}}
animationType="fade"
transparent={true}
>
<View style={styles.modalContainer}>
<ScrollView
showsVerticalScrollIndicator={true}
>
{dataForMaritalStatus === null ? <Text style={styles.nodata}>No data Found </Text> : dataForMaritalStatus.map((status, id) => (
<View key={id}>
<TouchableOpacity
style={styles.opacity}
onPress={() => {
this._toggleModal()
}}>
<Text style={styles.taskList}>{status.value}</Text>
</TouchableOpacity>
</View>
))}
</ScrollView>
</View>
</Modal>
*/
So how to make a common class for this component and pass different arrays of data and use it in render method ? The data is going to be different for different purposes and I need to maintain different states for different purposes.
Edit : I have written a method for it,but it calls the function but it does not render the modal, do I need to render it ?
createModal = (data) => {
<Modal visible={this.state.isModalVisible}
onRequestClose={() => {
this.setState({ isModalVisible: false })
}}
animationType="fade"
transparent={true}
>
<View style={styles.modalContainer}>
<ScrollView
showsVerticalScrollIndicator={true}
>
{data === null ? <Text style={styles.nodata}>No data Found </Text> : data.map((status, id) => (
<View key={id}>
<TouchableOpacity
style={styles.opacity}
onPress={() => {
this._toggleModal()
}}>
<Text style={styles.taskList}>{status.value}</Text>
</TouchableOpacity>
</View>
))}
</ScrollView>
</View>
</Modal>
}
Solution 1
Create a separate file customModalComponent.js, and pass in the array data through props. Change your Modal component a little bit, use this.props.dataForMaritalStatus for dataForMaritalStatus..
<ScrollView showsVerticalScrollIndicator={true}>
{this.props.dataForMaritalStatus === null ? <Text style={styles.nodata}>No data Found </Text>
: this.props.dataForMaritalStatus.map((status, id) => (
...
)}
</ScrollView>
and then on any other file, import CustomModal from './customModalComponent' and use it this way,
<CustomModal dataForMaritalStatus={yourArrayOfData}/>
Solution 2
If you are just using it in the same file, create a function instead
class myClass extends Component {
constructor(props) {
super(props);
this.createModal = this.createModal.bind(this);
}
render() {
...
}
createModal(dataForMaritalStatus) {
return (
//Insert your Modal code here
...
)
}
}
and use it this way in your render,
render() {
<View>
...
{
this.createModal(yourArrayOfData)
}
...
</View>
}
create new component in one folder.
app -> CommonModal.js
CommonModal.js
import React, { Component } from 'react';
import { View, Text, Modal, TouchableOpacity } from 'react-native';
export default class CommonModal extends Component{
constructor(props) {
super(props);
}
}
render(){
return(
<Modal visible={this.state.isModalVisible}
onRequestClose={() => {
this.setState({ isModalVisible: false })
}}
animationType="fade"
transparent={true}
>
<View style={styles.modalContainer}>
<ScrollView
showsVerticalScrollIndicator={true}
>
{this.props.dataForMaritalStatus === null ? <Text style={styles.nodata}>No data Found </Text> : this.props.dataForMaritalStatus.map((status, id) => (
<View key={id}>
<TouchableOpacity
style={styles.opacity}
onPress={() => {
this._toggleModal()
}}>
<Text style={styles.taskList}>{status.value}</Text>
</TouchableOpacity>
</View>
))}
</ScrollView>
</View>
</Modal>
)
}
note: i have used this.props.dataForMaritalStatus
And then use it wherever you need the component
app -> Second.js
Second.js
import React, { Component } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import CommonModal from './CommonModal';
export default class Second extends Component{
constructor(props){
super(props);
this.state={
dataForMaritalStatus:['val1','val2']
}
}
render(){
return(<View style={{flex:1}}>
<CommonModal dataForMaritalStatus={this.state.dataForMaritalStatus}/>
</View>)}
}
Create a separate component for Model
import React, { Component } from "react";
import { Text, View, Modal, ScrollView, TouchableOpacity, Text } from "react-native";
export default class CustomModel extends Component {
render() {
const { dataForMaritalStatus } = this.props;
return (
<Modal
visible={this.state.isModalVisible}
onRequestClose={() => {
this.setState({ isModalVisible: false });
}}
animationType="fade"
transparent={true}
>
<View style={styles.modalContainer}>
<ScrollView showsVerticalScrollIndicator={true}>
{dataForMaritalStatus === null ? (
<Text style={styles.nodata}>No data Found </Text>
) : (
dataForMaritalStatus.map((status, id) => (
<View key={id}>
<TouchableOpacity
style={styles.opacity}
onPress={() => {
this._toggleModal();
}}
>
<Text style={styles.taskList}>{status.value}</Text>
</TouchableOpacity>
</View>
))
)}
</ScrollView>
</View>
</Modal>
);
}
}
don't forget to export that component.
Now import that component in the file where you want to use that
import Model from "./CustomModel";
and use it this way
<CustomModel dataForMaritalStatus=[] />
you can pass data using props like a do above.
you can learn more about props here: https://facebook.github.io/react-native/docs/props

Trying to get the modal working in React Native

Attempting to get the modal working on my react native app. I want the more page to display a modal of more options. I have made the following attempt in regards putting the modal in the more menu page. The error I am currently getting is:
MoreMenu.js
import React, { Component } from 'react';
import { Modal, Text, TouchableHighlight, View } from 'react-native';
class MoreMenu extends Component {
state = {
modalVisible: false,
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={{marginTop: 22}}>
<Modal
animationType={"slide"}
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {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>
);
}
}
TabsRoot.JS
class Tabs extends Component {
_changeTab (i) {
const { changeTab } = this.props
changeTab(i)
}
_renderTabContent (key) {
switch (key) {
case 'today':
return <Home />
case 'share':
return <Share />
case 'savequote':
return <SaveQuote />
case 'moremenu':
return <MoreMenu />
}
}
render () {
const tabs = this.props.tabs.tabs.map((tab, i) => {
return (
<TabBarIOS.Item key={tab.key}
icon={tab.icon}
selectedIcon={tab.selectedIcon}
title={tab.title}
onPress={() => this._changeTab(i)}
selected={this.props.tabs.index === i}>
{this._renderTabContent(tab.key)}
</TabBarIOS.Item>
)
})
return (
<TabBarIOS tintColor='black'>
{tabs}
</TabBarIOS>
)
}
}
export default Tabs
You forget to export MoreMenu Component. and you use MoreMenu Component in TabsRoot.js.
pls add following line at the end of MoreMenu.js
export default MoreMenu

Modal View in React Native

I am new to react native, I am trying to present a view modally. I have a table view and when one of the rows is clicked I want the view to show up modally.
This is how I am implementing the transition right now :
renderbooks(books) {
return (
<TouchableHighlight onPress={() => this.showbooksDetail(books)} underlayColor='#dddddd'>
<View>
<View style={styles.container}>
<View style={styles.rightContainer}>
<Text style={styles.title}>{books.title}</Text>
</View>
</View>
<View style={styles.separator} />
</View>
</TouchableHighlight>
);
}
showbooksDetail(books){
this.props.navigator.push({
title:books.title,
component: ProductView,
passProps:{books}
});
}
How can I modify this so that the view can be presented modally?
FYI: I have already looked at multiple questions and sample projects such as these:
How do I create a native looking modal view segue with react-native?
http://facebook.github.io/react-native/docs/modal.html#content
https://github.com/aaronksaunders/React-Modal-Nav-Example
Check out the built-in Modal. It's implemented on iOS, Android implementation should come in one of the next releases of React Native.
The documentation contains an example on how to use it.
In your case it would be something like:
renderBooks(books) {
...
<Modal
animated={true}
transparent={true}
visible={!!this.state.selectedBook}>
<Text>{this.state.selectedBook.title}</Text>
</Modal>
...
}
showDetail(book) {
this.setState({
selectedBook: book,
});
}
Check this simple and powerful small library react-native-modal-animated, simply install it by yarn add react-native-modal-animated, or npm install react-native-modal-animated.
import { AnimatedModal } from 'react-native-modal-animated
<View style={styles.container}>
<TouchableOpacity
onPress={() => {
this.setState({ modalVisible: true });
alert
}}
style={styles.button}
>
<Text style={styles.buttonText}>Show Modal</Text>
</TouchableOpacity>
<AnimatedModal
visible={this.state.modalVisible}
onBackdropPress={() => {
this.setState({ modalVisible: false });
}}
animationType="vertical"
duration={600}
>
{/*Any child can be used here */}
<View style={styles.modalCard}>
<Text>I'm AnimatedModal</Text>
<Text style={{fontWeight: 'bold', marginTop: 10}}>vertical</Text>
</View>
</AnimatedModal>
</View>
);
}
}
I am using the react-native modalbox. Its been awesome you get modals to be displayed in top,center,bottom,etc.Check the below link once:https://github.com/maxs15/react-native-modalbox
Sample:
import React from 'react';
import Modal from 'react-native-modalbox';
import Button from 'react-native-button';
import {
AppRegistry,
Text,
StyleSheet,
ScrollView,
View,
Dimensions
} from 'react-native';
class Example extends React.Component {
constructor() {
super();
this.state = {
isOpen: false,
isDisabled: false,
swipeToClose: true,
sliderValue: 0.3
};
}
onClose() {
console.log('Modal just closed');
}
onOpen() {
console.log('Modal just openned');
}
onClosingState(state) {
console.log('the open/close of the swipeToClose just changed');
}
render() {
return (
<View style={styles.wrapper}>
<Button onPress={() => this.refs.modal1.open()} style={styles.btn}>Basic modal</Button>
<Button onPress={() => this.refs.modal2.open()} style={styles.btn}>Position top</Button>
<Button onPress={() => this.refs.modal3.open()} style={styles.btn}>Position centered + backdrop + disable</Button>
<Button onPress={() => this.refs.modal4.open()} style={styles.btn}>Position bottom + backdrop + slider</Button>
<Modal
style={[styles.modal, styles.modal1]}
ref={"modal1"}
swipeToClose={this.state.swipeToClose}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
<Button onPress={() => this.setState({swipeToClose: !this.state.swipeToClose})} style={styles.btn}>Disable swipeToClose({this.state.swipeToClose ? "true" : "false"})</Button>
</Modal>
<Modal style={[styles.modal, styles.modal2]} backdrop={false} position={"top"} ref={"modal2"}>
<Text style={[styles.text, {color: "white"}]}>Modal on top</Text>
</Modal>
<Modal style={[styles.modal, styles.modal3]} position={"center"} ref={"modal3"} isDisabled={this.state.isDisabled}>
<Text style={styles.text}>Modal centered</Text>
<Button onPress={() => this.setState({isDisabled: !this.state.isDisabled})} style={styles.btn}>Disable ({this.state.isDisabled ? "true" : "false"})</Button>
</Modal>
<Modal style={[styles.modal, styles.modal4]} position={"bottom"} ref={"modal4"}>
<Text style={styles.text}>Modal on bottom with backdrop</Text>
</Modal>
</View>
);
}
}
const styles = StyleSheet.create({
modal: {
justifyContent: 'center',
alignItems: 'center'
},
modal2: {
height: 230,
backgroundColor: "#3B5998"
},
modal3: {
height: 300,
width: 300
},
modal4: {
height: 300
},
wrapper: {
paddingTop: 50,
flex: 1
},
});
AppRegistry.registerComponent('Example', () => Example);