I am showing user a modal that takes over the entire screen if user is accessing the website on phone. A user tends to instinctively click the back button on their phone to go back to the previous screen instead of using the close button provided on the modal.
Is there a way to intercept the function that is triggered when a user clicks the back button? I want to close the modal when user clicks the back button on their phone, instead of having them redirect to the previous page.
Use the History API. An example on how to acomplish this is:
//listen for state changes
window.onpopstate = (event) =>
{
if (!event.state.modalOpened)
{
closeModal()
}
}
//change the actual page state so it contains the modalOpened property
window.history.replaceState({modalOpened: false})
function openModal(content)
{
//push new state, put the modal information in the state object, this will push a new state, when the user presses the back button, the browser will just trigger the onpopstate event, instead of going to the previous page
window.history.replaceState({modalOpened: true})
//this is any code you use to open your modal, for example
ReactDOM.render(<Modal>{content}</Modal>, document.getElementById("modal-container")
}
class based component
There are many ways to aproach this, this is one of them, everything you need to make something that fits with your app is in the History API DOCS.
//listen for state changes
window.onpopstate = (event) =>
{
if (!event.state.modalOpened)
{
updateModal(false, null)
}
}
function openModal()
{
//push new state, put the modal information in the state object, this will push a new state, when the user presses the back button, the browser will just trigger the onpopstate event, instead of going to the previous page
window.history.replaceState({modalOpened: true})
updateModal(false, <div>Modal content!</div>)
}
function updateModal(open, content)
{
ReactDOM.render(<Modal open={open} content={content} />, document.getElementById("modal-container")
}
//change the actual page state so it contains the modalOpened property
window.history.replaceState({modalOpened: false})
class Modal extends React.Component {
constructor(props) {
super(props);
}
render() {
//check the history to determine if we have to open or close the modal
return <div className={"modal " + (props.open)? "show" : ""}><div className="modal-content">{props.content}</div><button onClick={() => window.history.back()}>OK</button></div>;
}
}
Related
I have a button and when we press it, Firebase updates some value in Firebase. How can I control users? When we press it, Firebase updates some value in Firebase. How can I control users' presses? And allow the user to press this button only once?
My idea is that when opening some page in useEffect, I check if this user pressed a button earlier (I store all users' IDs to check if a user pressed a button) and if there is no user ID, then I allow the user to press the button, but if there is a user ID, then I disable the button and the user can't press it again.
But here is some problems. When user open page while firebase checks if there is user button is available for pressing. This is problem and I dont' want to allow do that.
And also if previosly user didn't press the button and now wants to do that then I need to imidiatelly disable it to prevent pressing it more than once.
How To disable button while data is fetched from firebase (on page loading)
How To disable button after 'click'
Here's a test component which accomplishes what you are asking:
import React, {useEffect, useState} from 'react';
import { Button } from 'react-native-paper';
const Test = props => {
const [isButtonDisabled, setIsButtonDisabled] = useState(false);
useEffect(() => {
const fetchMyAPI = async () => {
setIsButtonDisabled(true) // Disable button
let response = await fetch('api/data')
response = await response.json()
// Do whatever you want with response
setIsButtonDisabled(false) // Enable button after fetching
}
fetchMyAPI()
}, [])
const onPressHandler = () => {
setIsButtonDisabled(true)
// Button functionality can go here
}
return (
<Button onPress={onPressHandler} disabled={isButtonDisabled}></Button>
);
};
export default Test;
This is for react native so just replace the react native Button with whatever button you want to use.
Edit:
If you are having a problem with the button disabled state when reloading this component it is likely due to the component re-rendering. You will have to lift the state up to the parent and pass the state back down to the children. This will avoid the state being reset when the button gets re-rendered.
See the react docs https://reactjs.org/docs/lifting-state-up.html
I have a form which is written using formik and react-hooks. I am trying get recommendations on how to track a form change when user clicks home button or page refresh/reload?
I have tried, browser history method to trigger a modal to show unsaved changes
const unlisten = browserHistory.listen( location => {
//trigger modal here
});
But this seems to doesn't work. Also I am using react-router...if any suggestions using that will be helpful.
I am all done storing formvalues into a state using useState and setState,
I have a modal to show when exit button is clicked on form to track form changes but I am not sure how to detect outside of form.
I will put this here as a posible workaround to the question.
When you update your form in your handleChange method (whatever it is),you can also update user localstorage. With this approach you can check when page loads if there is some values in storage from older sessions or before.
Setting Values:
this.setState({ item1: value }, () => {
localStorage.setItem('myForm', JSON.stringify(this.state));
});
Getting values:
componentDidMount() {
const storedValues = JSON.parse(localStorage.getItem('myForm'))
this.setState({...storedValues});
}
Restore Data:
In your onSubmit method remember to clear localStorage
localStorage.removeItem('myForm');
I'm using react-router-navigation-prompt for exactly that purpose, it's made for react router. Just add this component inside your <Form/> / <form/>,
<NavigationPrompt
when={formProps.dirty}>
{({ isActive, onConfirm, onCancel }) => {
if (isActive) {
return (
<ConfirmationPopUp
isOpen
onConfirm={onConfirm}
onCancel={onCancel}
/>
);
}
}}
</NavigationPrompt>
So I have a bottom navigation bar with three tabs: HomeView, UploadVideo and Messages. Basically, what I would like to do is when the user clicks on the UploadVideo tab, it will behave kind of the way Instagram does it. Where it will open up the image library, and allow the to select a media item and moves them to a screen where they can enter in their details. And if the user goes through the upload process entirely or cancels it will take them back to the page they were originally on before clicking the Upload tab/button.
Currently, what I have is when the User clicks Upload Video it will open up a screen with the tab bar hidden with an icon to open the Image library and a form to enter in the video data. If the user clicks cancel it will take them back to the HomeView (programmed this way) regardless of where they were when they click on the UploadVideo tab. So basically I guess to summarize my question, how can I get a tab to act more as a button?
You could immediately open a picker when the tab is rendered and navigate away once a video has been selected, something like this:
class HomeTab extends React.Component {
render() {
return (
<View/>
);
}
}
class GalleryTab extends React.Component {
async componentDidMount() {
const {cancelled} = await ImagePicker.launchImageLibraryAsync(options);
if(cancelled){
navigation.goBack()
}
navigation.navigate('detailScreen')
}
render() {
return (
<View/>
);
}
}
const TabNavigator = createBottomTabNavigator({
Home: HomeTab,
Gallery: GalleryTab,
});
export default createAppContainer(TabNavigator);
Suppose my current route is /transact/orders and is in Order summary view, What I want to do is to open a custom dialog which gives the option to add to cart or cancel button when he/she presses browser back button of the browser.If user press add to cart button it goes to the cart or else the browser back button functionality will happen. Currently, I am using Angular 5.2.I would like to know if it is possible with LocationStrategy.I searched but could not get a proper example of it.Can anybody explain with proper example?
You can subscribe to Location events anywhere you want to do actions on back button pressed:
import { Subscription } from 'rxjs/Subscription';
ngOnInit() {
this.subscription = <Subscription> this.location.subscribe( () => {
// your code here
} );
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
Don't forget to unsubscribe in OnDestroy.
EDIT: location should be type Location, not LocationStrategy
Requirement: When clicking on a button that pushes a #info route to show a full screen overlay component, closing the modal or pressing back should dismiss the overlay rather than go to the previous page.
e.g. on page 1, go to page 2. On page 2, press button to show overlay. Press back or closing overlay should dismiss overlay and remain on page 2.
The problem: When going back to page 2 I still have forward history to go to the overlay route.
I've searched for ways and couldn't find a solution to delete forward history.
My code is as such: If overlay is shown:
this.props.router.push(this.props.router.getCurrentLocation().pathname + '#info')
Then I have a code to goBack when overylay is closed or when pressing back button:
onBackButtonEvent () {
if (this.props.renderOverlay) {
this.setState({
overlayRoutePushed: false
})
this.props.closeOverlay()
}
}
closeOverylayAndBack () {
this.setState({
overlayRoutePushed: false
})
this.props.closeOverlay()
this.props.router.goBack()
}
componentDidMount () {
window.onpopstate = this.onBackButtonEvent
}
In order to detect back button with window.onpopstate I have to push a route. I tried to replaceRoute with #info when overlay shown and just close overlay when pressing back but I can't prevent default of route.goBack().
Any ideas?
I wasn't able to find a way to prevent forward or remove forward history so my final resort was to remove using hash and just show the overlay when i hit forward and hide when I hit back:
this.props.router.push({
pathname: this.props.router.getCurrentLocation().pathname,
state: {overlay: true}
})
This is to remove the #, and if I don't change state push will actually be using replace() which won't let me handle onPopState.
Then I check to see if state is changed when I pop back and forth:
componentWillReceiveProps (nextProps) {
if (nextProps.router.location.state) {
if (nextProps.router.location.state.overlay) {
this.showOverylay()
}
}
}