everyone. I'm new in this new tecnology and I'm having a little problem with modals.
I'm programming a modal that only shows when a condition is true, in the first click it's all ok, but in the second the modal won't show, then when I click again, the window appears again, and continue successively.
The code works as follow: I have 3 states, each represent a different text to show in the modal. Then, I have a modal, that recieves a message (to print) and the state to identifies what state i need to show. And finally, in the main, I have a condition who calls the modal and show it ONLY if the state is true.
I checked the states with console.log and the only issue i find is that in some cases, the state is set in true, when is false, but i don't know why!
Thanks for read!
Here i detach part of the code.
Declare of the states in the main
const [modalVisibleEnTermino, setModalVisibleEnTermino] = useState(false)
const [modalVisibleFueraTermino, setModalVisibleFueraTermino] = useState(false)
const [modalVisibleRefuerzoTermino, setModalVisibleRefuezoTermino] = useState(false)
Condtition in main to show the apropiate state of modal
const setModal = () => {
vacunas ===2 && (days>6 && days<150) ? setModalVisibleEnTermino(true) : setModalVisibleFueraTermino(true)
if(vacunas == 3)
setModalVisibleRefuezoTermino(true)
}
Function to reset the states after showing modal (IDK if its ok)
const restoreModals = () => {
if (modalVisibleEnTermino) setModalVisibleEnTermino(false)
if (modalVisibleFueraTermino) setModalVisibleFueraTermino(false)
if (modalVisibleRefuerzoTermino) setModalVisibleRefuezoTermino(false)
}
After set the modal, I checked what state it's true, and I passed the values in this condition
{modalVisibleEnTermino && <MyModal
message={"Mensaje1"}
state={modalVisibleEnTermino}
/>
}
{modalVisibleFueraTermino && <MyModal
message={"Mensaje2."}
state={modalVisibleFueraTermino}
/>
}
{modalVisibleRefuerzoTermino && <MyModal
message={"Mensaje3."}
state={modalVisibleRefuerzoTermino}
/>
}
Modal
export const MyModal = (props) => {
const [visibleModal, setVisibleModal] = useState(props.state)
return (
<Modal visible={visibleModal}
transparent={true}
animationType='slide'
>
<View style={styles.container}>
<Text style={styles.titulo_label}>¡IMPORTANTE!</Text>
<Text style={styles.info_label}>{props.message}</Text>
<TouchableOpacity style={styles.button_aceptar} onPress={() => setVisibleModal(false)}>
<Text style={styles.text_button}>Aceptar</Text>
</TouchableOpacity>
</View>
</Modal>
);
Add a restore property to your MyModal component
{modalVisibleEnTermino && <MyModal
message={"Mensaje1"}
state={modalVisibleEnTermino}
restore={restoreModals}
/>
}
{modalVisibleFueraTermino && <MyModal
message={"Mensaje2."}
state={modalVisibleFueraTermino}
restore={restoreModals}
/>
}
{modalVisibleRefuerzoTermino && <MyModal
message={"Mensaje3."}
state={modalVisibleRefuerzoTermino}
restore={restoreModals}
/>
}
In the MyModal Component remove the useState and pass the props.state to visible and use the props.restore on the onPress callback like so
export const MyModal = (props) => {
return (
<Modal visible={props.state}
transparent={true}
animationType='slide'
>
<View style={styles.container}>
<Text style={styles.titulo_label}>¡IMPORTANTE!</Text>
<Text style={styles.info_label}>{props.message}</Text>
<TouchableOpacity style={styles.button_aceptar} onPress={() => props.restore()}>
<Text style={styles.text_button}>Aceptar</Text>
</TouchableOpacity>
</View>
</Modal>
);
In your original MyModal Component, by passing the props.state to useState, you are creating a new state within that component. Setting onPress to setVisibleModal(false) will not change the states of modalVisibleEnTermino, modalVisibleFueraTermino, and modalVisibleRefuerzoTermino. By passing restoreModals as a prop to MyModal you can change the states in the Main component from inside MyModal.
One more thing, remove the if statements in your restoreModals function
const restoreModals = () => {
setModalVisibleEnTermino(false)
setModalVisibleFueraTermino(false)
setModalVisibleRefuezoTermino(false)
}
Related
Nested TextInput component does not allow other components' onPress function to be called. Only when the TextInput is not focused, the onPress works fine.
React Native Version : 0.66.3
Here is my code
export const Component = (props): JSX.Element {
const { searchText, onChangeSearchText, onClearSearchText } = props
const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
return (
<View style={styles.searchBoxContainer}>
<View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
<Icon styles={styles.searchIcon} icon={searchIcon} />
<TextInput
style={styles.searchInput}
onChangeText={onChangeSearchText}
value={searchText}
onFocus={() => setSearchViewFocused(true)}
onBlur={() => setSearchViewFocused(false)}
autoCompleteType={"off"}
numberOfLines={1}
/>
{searchText !== "" && (
<Pressable style={styles.clearIcon} onPress={onClearSearchText}>
<Icon icon={cancelIcon} />
</Pressable>
)}
</View>
</View>
)
})
Attached are the images of
Expected.
VS
The issue
When the cross icon is pressed on focused state, the textInput is unfocused rather What I am trying to achieve is that the search text gets cleared & the input remains focused.
Note: The onPress works perfectly fine when input is not focused
Any help is appreciated. Thanks!
PS: Tried TouchableOpacity & also I have tried wrapping the components inside a ScrollView to use keyboardShouldPersistTaps='handled' as mentioned in one of the SO answer but to no success.
Found a workaround to this is to wrap the whole component into a ScrollView and adding the prop keyboardShouldPersistTaps='handled'
Previously I was making the View inside the Component as ScrollView and adding keyboardShouldPersistTaps='handled' which did not work
export const Component = (props): JSX.Element {
...
return (
<ScrollView contentContainerStyle={styles.searchBoxContainer}
keyboardShouldPersistTaps='handled'>
...
</ScrollView>
)
})
The key was to wrap the entire component inside the ScrollView,
Here's what worked:
<ScrollView keyboardShouldPersistTaps='handled'>
<Component {...props}/>
</ScrollView>
Guess this was a silly mistake, but worth pointing out!
You're setting the focus of the entire component based on whether the TextInput has focus. Since the clear button is outside the text input, pressing it causes the component to lose focus.
One solution is to store the TextInput instance in a ref. When the clear button is pressed, you can refocus the text input. I've copied your component below and added some new lines, which are marked in comments.
export const Component = (props): JSX.Element {
const { searchText, onChangeSearchText, onClearSearchText } = props
const textInputRef = useRef(null); // new
const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
const onClear = () => {
onClearSearchText();
textInputRef.current?.focus();
} // new
return (
<View style={styles.searchBoxContainer}>
<View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
<Icon styles={styles.searchIcon} icon={searchIcon} />
<TextInput
ref={textInputRef} // new
style={styles.searchInput}
onChangeText={onChangeSearchText}
value={searchText}
onFocus={() => setSearchViewFocused(true)}
onBlur={() => setSearchViewFocused(false)}
autoCompleteType={"off"}
numberOfLines={1}
/>
{searchText !== "" && (
<Pressable style={styles.clearIcon} onPress={onClear}> // calls new function
<Icon icon={cancelIcon} />
</Pressable>
)}
</View>
</View>
)
})
good morning
I wanted to send some array data to child component , the purpose of this component is to make my code in one page shorter
this page i named it homepage, inside homepage there are multiple charts
import Chart01 from ../components/chart01
import Chart02 from ../components/chart02
import Chart03 from ../components/chart03
and in this homepage there will be buttons that (I'm planning to) send value to those 3 charts
const [FirstValue,setFirstValue] = useState(0)
return(
<View>
<View>
<Button onPress={()=>setFirstValue(1)}
<Button onPress={()=>setFirstValue(2)}
<Button onPress={()=>setFirstValue(3)}
</View>
<Chart01/>
<Chart02/>
<Chart03/>
</View>
)
How do i send the FirstValue from HomePage to Chart01 Chart02 Chart03 ?
and in Chart01, how do I call value that sent from HomePage ?
Thank you
In home you have pass like below,
<Chart01 value={FirstValue}/>
<Chart02 value={FirstValue}/>
<Chart03 value={FirstValue}/>
In Chart01,02,03 definition, you have to read props.
const Chart01 = (props) => {
const { value } = props;
// someting
};
Pass the values as props to the chart components.
const [firstValue, setFirstValue] = useState(0);
return(
<View>
<View>
<Button onPress={() => setFirstValue(1)}
<Button onPress={() => setFirstValue(2)}
<Button onPress={() => setFirstValue(3)}
</View>
<Chart01 value={firstValue} />
<Chart02 value={firstValue} />
<Chart03 value={firstValue} />
</View>
);
Within the chart components you can access the passed value from the value prop (or whatever you name it). For example:
props.value
I would like to show modal when the user enabled the switch or disabled. what should i do to achieved what i want? this is my current code. I am new in this technology, I hope you all understand , Please bear with me. thanks
import {SimpleModal} from '../../components/modal/Modal';
const [isModalVisible, setisModalVisible] = useState(false);
const changeModalVisible=(bool) =>{
setisModalVisible(bool);
}
const confirmDelete = (id,status) =>{
console.log("changeModalVisible: ",changeModalVisible(true))
if (status == 0){
if (changeModalVisible(false)) {
handleDelete(id,status);
} else {
alert("error")
}
}else{
if (changeModalVisible(true)) {
handleActivate(id,status);
} else {
}
}
}
<FlatList
keyExtractor={(item, index) =>index.toString()}
data={documentlists}
renderItem={({ item }) => (
<DocumentLocation
key={item.name}
status={item.status}
editHandler={handleEdit}
pressHandler={confirmDelete}
/>
)}
/>
<Modal
transparent={true}
animationType='fade'
visible={isModalVisible}
nRequestClose={() => changeModalVisible(false)}
></Modal>
<SimpleModal/>
component/model/Model.js
const SimpleModal = () => {
return (
<TouchableOpacity
disabled={true}
style={formStyles.container}
>
<View>
<View>
<Text>
Sample modal header
</Text>
<Text>
Sample modal description
</Text>
</View>
</View>
</TouchableOpacity>
)
}
work flow, if the client switch the toggle popup modal will appear,
in the modal, i want two button that is ok and cancel, if the user click the ok, the data will updated and if cancel, no updated data, note the functionality of updating data is already working, my problem is the modal , please refer to this image
As per your comment this is the flow you expect.
User clicks switch in flatlist
If the value is false the status is updated
If value is true, a confirmation Modal is shown.
There are some changes required
renderItem={({ item,index }) => (
<DocumentLocation
key={item.name}
status={item.status}
editHandler={handleEdit}
pressHandler={(value)=>confirmDelete(value,index)}
/>
)}
Here the value should come from the switch
instead of using the showModalVisible have a state to manage the selectedIndex
const [selectedIndex, setSelectedIndex] = useState(-1);
If an item is changed to true we set the selectedIndex
We use that to control the visibility of the modal
<Modal visible={selectedIndex > -1} onRequestClose={() => setSelectedIndex(-1)}>
<Text>Approve?</Text>
<Button
title="Yes"
onPress={() => {
updateSelectedItem(selectedIndex, true);
setSelectedIndex(-1);
}}
/>
<Button title="No" onPress={() => setSelectedIndex(-1)} />
</Modal>
The buttons in the Modal will rest the selected index or update the array.Something like the below function.
const updateSelectedItem = (index, value) => {
const updatedData = [...data];
updatedData[index].active = value;
setData(updatedData);
};
Sample code
https://snack.expo.io/#guruparan/verifypopup
You should enclose your SimpleModal component in the Modal, like this -
<Modal
transparent={true}
animationType='fade'
visible={isModalVisible}
nRequestClose={() => changeModalVisible(false)}
>
<SimpleModal/>
</Modal>
for modals use https://github.com/jeremybarbet/react-native-modalize
this library saved me a lot of days and pain developing modals in my app
if you are not using typescript, change the ref from
const modalizeRef = useRef<Modalize>(null);
to
const modalizeRef = useRef(null);
I have a modal - react-native-modal - I want when it pops up and the user pressed out of the modal's Box that should disappear the modal , so i have used TouchableOpacity it works only if you click inside the box please see my image attached file.
this is my code :
import Modal from 'react-native-modal';
const TeskModal = ({isVisibles, onCallBaclk, deleteCurrenteTask , hideit}) => (
<View>
<TouchableOpacity onPress ={ () => hideit()}>
<Modal
isVisible = {isVisibles}
animationIn = {'zoomInDown'}
animationOut = {'zoomOutUp'}
animationInTiming = {500}
animationOutTiming = {500}
backdropTransitionInTiming = {1000}
backdropTransitionOutTiming = {1000}
>
<TouchableOpacity onPress ={ () => hideit()}>
<View style={style.modal}>
<View style={style.textView}>
<Text>
Change State Or Delete.
</Text>
</View>
<View style = {style.buttonView} >
<Button style={style.buttonChangeStatus} title ="Delete Task" onPress ={ () => deleteCurrenteTask()} />
<Button style={style.buttondelete} title = " Change State" onPress ={ () => onCallBaclk()} />
</View>
</View>
</TouchableOpacity>
</Modal>
</TouchableOpacity>
</View>
);
export default TeskModal;
here is my image
could you please help me to solve this issue.
There is a function called onBackdropPress in react-native-modal. You can call a function when the backdrop(i.e. outside the area of the modal) is pressed.
<Modal
{... otherProps }
onBackdropPress = {() => hideIt()}
/>
The above code will do it fo you.
There is a prop that you can pass which will take care of performing the function that you pass to the prop in case user press outside of the modal box. This way you will not need hideit()}> etc.
eg:
<Modal
isVisible={isVisible}
{...otherProps}
onBackdropPress={this.hideit()}>
{...content}
</Modal>
I hope this helps. Please let me know if this is what you are looking for.
I am new to react native.
My question is pretty simple: my screen contains 5 buttons. Each one opens the same < Modal > component. I need to dynamically change the content of the modal, depending on the button clicked.
For example:
if I click the first button, a text input will be shown into the modal.
If I click the second button, checkboxes will be shown into the modal.
Here's my modal :
<Modal
visible={this.state.modalVisible}
animationType={'slide'}
onRequestClose={() => this.closeModal()}>
<View style={style.modalContainer}>
<View style={style.innerContainer}>
<Text>This is content inside of modal component</Text>
<Button
onPress={() => this.closeModal()}
title="Close modal"
>
</Button>
</View>
</View>
</Modal>
Here I open it :
openModal() {
this.setState({ modalVisible: true });
}
Here I call the function (on button press) :
onPress={() => this.openModal()}
I've heard about using props/children, but I don't know how to use them is this case.
Can anyone please help ?
Here is quick example to show who to render different content based on input you provide.
Modal Content
renderModalContent(type, data) {
switch(type) {
1: {
return (
<View>{..data}</View>
)
}
2: {
return (
<Button>...</Button>
)
}
default: (<CustomComponent data={data} />)
}
}
Modal
<Modal>
<View>
{this.renderModalContent(this.state.type, this.state.modalContentData)}
</View>
</Modal>
Here you decide which view you want to render and pass its data.
openModal() {
this.setState({ modalVisible: true, type: 1, data: {...} });
}
You should modify your Modal component so that it renders the base layout with space for dynamic content to be rendered. The content will be passed in as children, via Props. This will mean the modal is dynamic and will / should support future requirements. Try to avoid the switch case in the modal render suggestion unless you have very specific requirements that are unlikely to change in the future, or if you want to do things the React way.
Then for each variant of your Modal (TextInput, Checkbox etc.) create a new Component that wraps the Modal component and have each button initiate rendering the specific component.
If you're using Redux then you would be creating containers, connecting to Redux and passing dynamic state variables. You don't have to use Redux but the principle is the same.
Here's a very basic example to illustrate my point.
// Basic modal that renders dynamic content
const Modal = props => {
const { children } = props;
render (
<View style={styles.modal} >
{children}
</View>
);
}
// Specific modal implementation with TextInput
const ModalWithTextInput = props => (
<Modal>
<TextInput
value={props.someValue}
/>
</Modal>
)
// Specific modal implementation with Switch
const ModalWithSwitch = props => (
<Modal>
<Switch
value={props.someValue}
/>
</Modal>
)
Then in your component that launches the modals, do something like this...
class MyComponent extends Component {
openTextModal = () => {
this.setState({ modalType: 'text' });
}
openSwitchModal = () => {
this.setState({ modalType: 'switch' });
}
renderModal = (type) => {
if (type === 'text') {
return(<ModalWithTextInput />)
}
if (type === 'switch') {
return(<ModalWithSwitch />)
}
}
render() {
const { modalType } = this.state;
render (
<View>
<View>
<TouchableWithX onPress={this.openTextModal} />
<TouchableWithX onPress={this.openSwitchModal} />
</View>
<View>
{this.renderModal(modalType)}
</View>
</View>
);
}
}
Please note this code has not tested but the principle is sound.