I have an ionic 3 app based on the super template. I have set the root page to the following:
<ion-tabs>
<ion-tab [root]="tab1Root" [tabTitle]="tab1Title" tabIcon="bonfire"></ion-tab>
<ion-tab [root]="tab2Root" [tabTitle]="tab2Title" tabIcon="search"></ion-tab>
<ion-tab [root]="tab3Root" [tabTitle]="tab3Title" tabIcon="cog"></ion-tab>
</ion-tabs>
When I press the hardware back button on this page, nothing happens at all. However, when I change the content to something else, like:
<p>Hello</p>
Then the hardware back button exits, as I would like.
How can I make the hardware back button work correctly on the tabbed page, while preserving the working default behaviour on other pages?
Inside your app.component.ts file
import { Nav, App } from 'ionic-angular';
export class MyApp {
#ViewChild(Nav) nav: Nav;
and then
platform.registerBackButtonAction(() => {
let nav = app.getActiveNav();
let activeView: ViewController = nav.getActive();
if(activeView != null){
if(nav.canGoBack()) {
nav.pop();
}else if (typeof activeView.instance.backButtonAction === 'function')
{
activeView.instance.backButtonAction();
}
else {
nav.parent.select(0); // goes to the first tab
}
}
});
Hope this helps you and also don't forget to place it inside the platform.
in your respcted ts file where you need to close the application write a funtion
backButtonAction(){
this.platfrom.exitApp();
}
I ended up needing to do this in app.container.ts to get the desired behaviour:
platform.registerBackButtonAction(() => {
let nav = app.getActiveNav();
let activeView = nav.getActive();
if (activeView != null){
if (nav.canGoBack()) {
nav.pop();
} else if (nav.parent.getSelected() != nav.parent.getByIndex(0)) {
// goes to the first tab
nav.parent.select(0);
} else {
platform.exitApp();
}
}
});
In your Tabs Page try to Add ionViewDidEnter and try to append the following class as follows:
ionViewDidEnter() {
this.platform.registerBackButtonAction(() => {
this.platform.exitApp();
});
}
Write your code inside the constructor() from which page you to leave.
Home.ts
constructor(
public navCtrl: NavController,
private platform: Platform) {
this.platform.registerBackButtonAction(()=>{
this.platform.exitApp();
});
}
Related
I'm still rather new to Ionic 4. I'm making an App that receives push notification. The navigation inside the app works like this:
Home page -> Detail page
Every time the user taps on the notification, the app will open and navigates to Detail page. The navigation works but since the navigation history is empty, if the user taps on the hardware back button, the app exits. I want it to redirect the user to Home page instead.
How do I achieve this in Ionic 4? is there any way to push a page to navigation history? I have read the documentation but couldn't find anything about this. The closest was probably NavCtrl.push() but it's no longer usable in Ionic 4.
Thank you.
There may be an easier way to do this but the following approach is a very flexible one because it'd allow you to run any custom logic when the user wants to go back from the page shown after a push notification or a deep link is opened.
Please take a look at this StackBlitz demo.
Please notice that in the demo, I'm redirecting to the DetailsPage as soon as the app is loaded because of the following code from the app-routing.module file:
{
path: "",
redirectTo: "/details/1?fromDeepLink=true", // <-- here!
pathMatch: "full"
}
Anyway, the important part happens in the DetailsPage. There, you need to handle what happens when the user tries to go back using a) the back button from the header and b) the physical back button from Android devices
The code is pretty self-explanatory, but basically in that page I'm looking for the fromDeepLink query string param, and if it's true, the app will register a custom action for both the back button from the header and for the physical back button from Android devices.
The custom action sets the HomePage as the root page, but sets the animationDirection parameter to be 'back'. That way it'd look like the user is going back to that page even if we're actually adding it to the navigation stack.
It's important to notice that this custom handler is being removed as soon as the user leaves the page so that we don't affect the default behaviour of the back button in any other pages.
import { Component, OnInit, ViewChild } from "#angular/core";
import { ActivatedRoute } from "#angular/router";
import { IonBackButtonDelegate, NavController, Platform, ViewDidEnter, ViewWillLeave } from "#ionic/angular";
import { Subscription } from "rxjs";
#Component({
selector: "app-details",
templateUrl: "./details.page.html",
styleUrls: ["./details.page.scss"]
})
export class DetailsPage implements OnInit, ViewDidEnter, ViewWillLeave {
#ViewChild(IonBackButtonDelegate, { static: false })
public backButton: IonBackButtonDelegate;
public itemId: number;
public fromDeepLink: boolean = false;
private unregisterBackButtonAction: Subscription;
constructor(
private platform: Platform,
private route: ActivatedRoute,
private navCtrl: NavController,
) {}
ngOnInit() {
const itemIdParam = this.route.snapshot.paramMap.get("itemId");
const fromDeepLinkParam = this.route.snapshot.queryParamMap.get('fromDeepLink');
this.itemId = +itemIdParam;
this.fromDeepLink = fromDeepLinkParam
? fromDeepLinkParam.toLocaleLowerCase() === 'true'
: false;
}
ionViewDidEnter() {
if(this.fromDeepLink) {
this.initializeCustomBackButtonAction()
}
}
ionViewWillLeave() {
if(this.fromDeepLink) {
this.removeCustomBackButtonAction();
}
}
private initializeCustomBackButtonAction(): void {
const leavingCallback = () => {
console.log('Using custom back button action');
this.navCtrl.navigateRoot('/home', { animationDirection: 'back' });
};
// Override the back button from the header
if (this.backButton) {
this.backButton.onClick = leavingCallback;
}
// Override the physical back button from Android devices
this.unregisterBackButtonAction = this.platform.backButton.subscribeWithPriority(10, leavingCallback);
}
private removeCustomBackButtonAction(): void {
this.unregisterBackButtonAction?.unsubscribe();
}
}
Please also notice that by default the ion-back-button is not shown if there's no page before the current page in the navigation stack, so in the demo I'm setting the defaultHref property like this:
<ion-back-button defaultHref></ion-back-button>
I'm leaving it empty because the component is actually going to override what this back button does with my custom back button action. But the defaultHref needs to be added to the template, otherwise the back button won't be shown.
I came across an issue in my android app which i have developed using ionic 4.
My scenario is if i navigate through pages and came back using toolbar back button and again navigate to another pages and came back using android hardware back button then the pages i navigated back using toolbar back button shows in middle while using hardware back button.
Page A->B->C and then on toolbar back button C->B->A
Again page navigate A->D->E and then using hardware back button page navigate E->D->B->C->B->A
Unable to maintain state.
My Code
In app.component.ts constructor
this.router.events.subscribe(event => {
const url = this.router.url //current url
if (event instanceof NavigationEnd) {
const isCurrentUrlSaved = this.navLinksArray.find((item) => { return item === url });
if (!isCurrentUrlSaved) this.navLinksArray.push(url);
}
});
ngAfterViewInit() {
this.backButtonSubscription = this.platform.backButton.subscribe(() => {
if (this.router.url === '/tabs/home') {
navigator['app'].exitApp();
} else {
if (this.navLinksArray.length > 1) {
this.navLinksArray.pop();
const index = this.navLinksArray.length - 1;
const url = this.navLinksArray[index];
this.navCtrl.navigateBack(url);
}
}
});
}
}
Thanks in advance.
I think, this.navCtrl.navigateBack(url); is pushing pages again like behavior is asynchronous just assuming.
Why dont you just pop the navigated page, lets say you have a generic function
ngAfterViewInit() {
static BackButton(platform:Platform,navCtrl:NavController){
platform.registerBackButtonAction(() => {
navCtrl.pop();
}, 0)
}
}
and from the navigated page component just call, which must have
constructor(public navCtrl: NavController,public platform:Platform){}, defined and then call generic method BackButton(this.platform,this.navCtrl) in same navigated page component.
I have splash screen on my apps, so I want to exit the apps when we click android back button from the main page (not go back to splash screen). So I want to implement this method from react-native tutorial.
if (!this.onMainScreen()) {
this.goBack();
return true;
}
return false;
Is there anyone can help me how to implement onMainScreen(), and goBack() functions?
Thank you for the help.
you should be able to use this function
function getCurrentRouteFromState(navigationState): NavigationRouteConfigMap {
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getCurrentRouteFromState(route);
}
return route;
}
pass it your navigation state and access the routeName member on the resulting object:
let screenName = getCurrentRouteFromState(state).routeName then you can compare the screen name with your main screen name and decide what to do.
So, On your main page(I think which is your Main.js)
import { BackHandler } from 'react-native';
componentWillMount(){
BackHandler.addEventListener('hardwareBackPress', function() {
BackHandler.exitApp();
});
}
I have redirected my app from app.component.ts by setting rootpage as follow
rootPage:any=HomePage;
Later when I implemented login functionality I decided to redirect page as follow
rootPage:any;//=HomePage;
constructor(platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
private storage: Storage,
private changeDetectorRef: ChangeDetectorRef) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
// Check session and redirect
storage.get('session').then((val) => {
if(val){
this.rootPage=HomePage;
}else{
this.rootPage=LoginPage;
}
});
});
}
But my page is not redirecting .
What I tried -
1. Page is redirecting when I am using this.changeDetectorRef.detectChanges() after setting rootpage, but my map in homepage is not loading when I am redirecting this way.
Is there any better solution to this problem?
The problem probably is that you assign the page to rootPage inside a promise. Because it is an async operation, the component renders before it is a assigned a root page. To fix it, you can simply use navCtrl.setRoot instead and wait to hide the splashscreen.
ngOnInit() {
platform.ready().then(() => {
// Check session and redirect
storage.get('session').then((val) => {
statusBar.styleDefault();
splashScreen.hide();
if (val) {
this.navCtrl.setRoot(HomePage);
} else {
this.navCtrl.setRoot(LoginPage);
}
});
});
}
Since you're not initializing root page anymore, I would also recommend doing this in ngOnInit instead of the constructor. It wasn't the cause of your problem, but it is recommended to do so.
Everything worked fine when I redirected user from ngOnInit() as follow
ngOnInit() {
// Check session and redirect
this.storage.get('session').then((val) => {
if(val){
this.rootPage=HomePage;
}else{
this.rootPage=LoginPage;
}
});
}
I'm working on making an Android app using Phonegap and AngularJS. I'm attempting to create a button to be used as both a "cancel" and a "back" button, that will essentially just hit the browser's 'back' button.
Here's some sample HTML for the cancel button:
cancel
And here is the controller for that page, with the goBack() button:
function NewOccasionCtrl($scope, $window) {
$scope.$window = $window;
$scope.goBack = function() {
$window.history.back();
};
}
This throws no errors, but also doesn't work... the emulator remains on the same page. Without the $scope.$window = $window it throws an error. I was hoping to achieve a functional 'back' button without having to create/use a directive, because as far as I understand those then implement templating and things I don't need/want.
Is there a way to do this? Thanks
I went with using a Directive to make the back functionality reusable. Here is my final code:
HTML:
<a href back-button>back</a>
Javascript:
app.directive('backButton', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', goBack);
function goBack() {
history.back();
scope.$apply();
}
}
}
});
I had an issue like this using phonegap and angular, $window.history.back() would not work. So I created a workaround.
$scope.urlHistory = [];
$scope.$on('$routeChangeSuccess', function () {
if ($location.$$absUrl.split('#')[1] !== $scope.urlHistory[$scope.urlHistory.length - 1]) {
$scope.urlHistory.push($location.$$absUrl.split('#')[1]);
}
});
$scope.goBack = function () {
$scope.urlHistory.pop();
$location.path($scope.urlHistory[$scope.urlHistory.length - 1]);
};
Hope this help someone else.