android default back button to be controlled in Ionic 4 - android

using ionic 4 i have created an application in that i need to control back button. I have used the following code
this.backButtonSubscription =
this.platform.backButton.subscribeWithPriority(1, async () => {
if (this.router.url === '/registration') {
navigator['app'].exitApp();
}
});
This subscription event is working only on root page and not working on other pages.
I want to control the back button on particular page to show alert and other things, but right now when clicking hardware back button in android device it goes to the previous page.

Code below works for me absolutely fine.
In initializeApp() method in app.component.ts
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleLightContent();
this.splashScreen.hide();
this.platform.backButton.subscribeWithPriority(9999, () => {
if(this.router.url !== '/login') {
// Back button controls when user is not in Login Page
} else {
navigator['app'].exitApp();
}
});
});
}

if you want the backButton to do Alert or Toast
Create the backButton function:
backButton() {
this.platform.backButton.subscribeWithPriority(0, () => {
this.showAlertBack();
});
}
Create the Alert Function:
async showAlertBack() {
const alert = await this.alertCtrl.create({
message: 'Want to Exit App?',
buttons: [
{
text: 'Ok',
handler: () => {
navigator['app'].exitApp();
}
},
{
text: 'Nop',
handler: () => {
alert.dismiss();
}
}
],
backdropDismiss: false
});
await alert.present();
}
Now Initialize it in ngOnInit() or ionViewWillEnter()
this.backButton();

Related

How to prevent going back in React Native using React Navigation and 'beforeRemove' eventListener with custom modal?

What I want to achieve is straightforward. I want the user to be forced to confirm exiting a tab navigator called 'checkout'.
I read on React Navigation docs about preventing going back about the 'beforeRemove' event which seems neat and the right thing to use.
The problem is that in their example they call Alert in the eventlistener whereas I want to show a custom modal with a yes and no button.
This is React Navigations example code:
function EditText({ navigation }) {
const [text, setText] = React.useState('');
const hasUnsavedChanges = Boolean(text);
React.useEffect(
() =>
navigation.addListener('beforeRemove', (e) => {
if (!hasUnsavedChanges) {
// If we don't have unsaved changes, then we don't need to do anything
return;
}
// Prevent default behavior of leaving the screen
e.preventDefault();
// Prompt the user before leaving the screen
Alert.alert(
'Discard changes?',
'You have unsaved changes. Are you sure to discard them and leave the screen?',
[
{ text: "Don't leave", style: 'cancel', onPress: () => {} },
{
text: 'Discard',
style: 'destructive',
// If the user confirmed, then we dispatch the action we blocked earlier
// This will continue the action that had triggered the removal of the screen
onPress: () => navigation.dispatch(e.data.action),
},
]
);
}),
[navigation, hasUnsavedChanges]
);
return (
<TextInput
value={text}
placeholder="Type something…"
onChangeText={setText}
/>
);
}
This is the code I have tried:
useEffect(() => {
navigation.addListener('beforeRemove', e => {
if (userConfirmedExit) {
navigation.dispatch(e.data.action);
} else {
e.preventDefault();
setShowExitModal(true);
}
});
}, [navigation, userConfirmedExit]);
const handleConfirmExit = () => {
setUserConfirmedExit(true);
navigation.replace('ProfileTab');
};
const handleDeclineExit = () => setShowExitModal(false);
I am bound to use the navigation.dispatch(e.data.action) inside the eventListener but the handleConfirmExit function must live outside of it and I just can't figure out how to use the beforeRemove listener AND showing a custom modal from where I can exit the tab.
The listener is firing when pressing the back button and the modal shows but nothing happens when pressing yes (i.e running the handleConfirmExit function).
I have tried removing dependencies from the useEffect. The one thing that did work, but only on Android was this:
useEffect(() => {
navigation.addListener('beforeRemove', e => {
e.preventDefault();
setShowExitModal(true);
});
}, [navigation]);
const handleConfirmExit = () => {
navigation.removeListener('beforeRemove', () => {});
navigation.replace('ProfileTab');
};
const handleDeclineExit = () => setShowExitModal(false);
On iOS the modal stays onto the next screen for some reason and the culprit I think is the bad implementation of 'beforeRemove' listener in the last example.
Thank you!
I have a simple solution
navigation.addListener('beforeRemove', (e) => {
if (e.data.action.type !="GO_BACK") {
//"GO_BACK" is emitted by hardware button
navigation.dispatch(e.data.action);
} else {
//your code to prevent hardware back button goes here } //
} )
use BackHandler , you can use navigation.goBack() instead of BackHandler.exitApp()
import { BackHandler} from "react-native";
const backAction = () => {
Alert.alert("Discard changes?", "Are you sure you want to exit?", [
{
text: "NO",
onPress: () => null,
style: "cancel"
},
{ text: "YES", onPress: () => BackHandler.exitApp() }
]);
return true;
};
useEffect(() => {
BackHandler.addEventListener("hardwareBackPress", backAction);
return () => {
BackHandler.removeEventListener("hardwareBackPress", backAction);
}
}, []);
This is what I did and it works fine, but I am sure there is a better solution out there.
const [showExitModal, setShowExitModal] = useState(false);
let exitEvent = useRef<
EventArg<
'beforeRemove',
true,
{
action: Readonly<{
type: string;
payload?: object | undefined;
source?: string | undefined;
target?: string | undefined;
}>;
}
>
>();
useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', e => {
e.preventDefault();
exitEvent.current = e;
setShowExitModal(true);
});
return unsubscribe;
}, [navigation]);
const handleConfirmExit = () => {
if (exitEvent.current) {
navigation.dispatch(exitEvent.current.data.action);
}
};
In the markup:
{showExitModal && (
<CheckOutExitModal
onYesPress={handleConfirmExit}
/>
)}

Android back button is applied to all the screens react native Error

I have added a function to disable the back button press in particular screen on my app. after the I have gone away from this screen back button is disabled in the whole app. The back button is disabled after that. following is my code
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
(async () => {
// console.log('param name.....',itemId)
const time = await AsyncStorage.getItem('#timer_set')
setEndTime(time);
const backhandler = BackHandler.addEventListener('hardwareBackPress', () => {
return true;
});
return () => {
backhandler.remove();
};
})();
});
return unsubscribe;
}, [navigation]);
Use BackHandler.removeEventListener.
useEffect(() => {
const backButtonHandler = () => {
return true;
}
BackHandler.addEventListener("hardwareBackPress", backButtonHandler);
return () =>
BackHandler.removeEventListener("hardwareBackPress", backButtonHandler);
}, []);

Back button is not disabling for particular screen in android React native

I am trying to disable android back button on home screen only.
My code:
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
navigation.goBack(null);
return true
}
const navigateToNextScreen = () => {
navigation.push('Prmotions');
}
If I remove navigation.goBack(null); back button is disabled for all screen and with above code back button is not disabled at all.
navigation.navigate("ScreenName") isn't working for mu scenario to move to next screen that's why I have used navigation.push
I handled it by putting this on all screens where I wanted to go back on back button press.
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
navigation.goBack(null);
return true
}
and put this where I wanted not to go back.
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
return true
}
I know this might not be best solution but it worked for me pretty well.

How to create global android device back button handler using React Native?

In my scenario, I am trying to create global class for android back button handler and reuse it in multiple screen class files. How to do it? I tried below code but I dont know how to access common class from other classes.
My Code Below (Androidhandler.tsx)
export default class hardware extends Component {
constructor(props) {
super(props);
this.BackButton = this.BackButton.bind(this);
}
componentWillMount() {
BackHandler.addEventListener'BackPress',this.BackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('BackPress',this.BackButton);
}
BackButton() {
if(this.props.navigation){
this.props.navigation.goBack(null);
return true;
}
}
}
the following code allows to show an alert when you want to go back with the android back button, what you need is to use the react native BackHandler component as follows.
import { BackHandler } from "react-native"
export default class hardware extends Component {
constructor(props) {
super(props);
this.BackButton = this.BackButton.bind(this);
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.BackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', () => {
if (this.props.navigator && this.props.navigator.getCurrentRoutes().length > 1) {
this.navigator.pop();
return true;
}
return false;
});
}
BackButton() {
Alert.alert(
'Warning',
'Are you sure to leave?',
[
{
text: 'Cancel',
style: 'cancel'
},
{ text: 'OK', onPress: () => BackHandler.exitApp() }
],
);
return true;
}
}

React Native BackHandler not removing event Listener

I am using React Navigation and I need some custom functionality when back button is pressed. Here is my code:
class AddEditIngredient extends Component {
constructor(props) {
super(props);
this.state = {
editStarted: false
};
this.goBack = () => {
if (this.state.editStarted === true) {
Alert.alert(
"Ingredient Not Saved",
"Do you want to navigate away without saving ingredient?",
[
{ text: "Cancel", onPress: () => null, style: "cancel" },
{ text: "Yes", onPress: () => this.props.navigation.goBack() }
],
{ cancelable: true }
);
} else {
this.props.navigation.goBack();
}
};
}
componentWillMount() {
BackHandler.addEventListener("hardwareBackPress", this.goBack);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.goBack);
}
My goBack function works fine for back button on screen, however when I try to press the physical back button it pops out all the screens and minimizes the application. From what I have gathered by reading previous posts on the issue, removeEventListener is not referring to the same function as addEventListener. So I tried this:
constructor(props) {
super(props);
this.state = {
editStarted: false
};
this.goBack = this.goBack.bind(this);
}
goBack = () => {
if (this.state.editStarted === true) {
Alert.alert(
"Ingredient Not Saved",
"Do you want to navigate away without saving ingredient?",
[
{ text: "Cancel", onPress: () => null, style: "cancel" },
{ text: "Yes", onPress: () => this.props.navigation.goBack() }
],
{ cancelable: true }
);
} else {
this.props.navigation.goBack();
}
};
But it didn't work. Can anyone point out my mistake?
Thanks
you need to attach return true on your custom back listener or return false to follow your parent handler
Finally found the answer in this post. I needed to return true at the end of my goBack function to indicate that back behaviour has been handled.

Categories

Resources