Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement platform hardware back button functions #5071

Closed
mhartington opened this issue Jan 18, 2016 · 44 comments
Closed

Implement platform hardware back button functions #5071

mhartington opened this issue Jan 18, 2016 · 44 comments
Assignees
Milestone

Comments

@mhartington
Copy link
Member

From @ydeshayes on November 6, 2015 11:3

Hello,

when i tap the android (hardware or not) back button, the app closed. I see in the code that a function is predicted but not implemented (https://github.com/driftyco/ionic2/blob/076dc7645edfd2d216a8f0f7bf52abca6b6be35e/ionic/platform/platform.ts line 161).

Did you think about integrate this back button with the navigation behavior ? (touching the android back button call navigation.pop() for example) or do we have to implement it ourselves ?

thanks !

Copied from original issue: driftyco/ionic2#462

@mhartington
Copy link
Member Author

From @adamdbradley on November 7, 2015 16:1

Yes Ionic be able to handle this like it did in v1, just haven't completed it yet.

@phavre
Copy link

phavre commented Jan 21, 2016

Agree, nice to have

@tomsun
Copy link
Contributor

tomsun commented Feb 4, 2016

FYI I'm using something like this as a workaround, until Ionic 2 provides something. Seems to get the job done... Not entirely generic though.

This particular app has a sub-page with a Tabs component, i.e. multiple NavControllers are involved - hence some additional complexity.

(If a Modal is active, the back button still exits the app when using this code)

app.js

import {ViewChild} from 'angular2/core';
import {App, Platform, NavController} from 'ionic/ionic';
import {RootPage} from './pages/root/root';
import {TabsPage} from './pages/tabs/tabs';

@App({
  template: '<ion-nav #rootNavController [root]="root" #content swipe-back-enabled="false"></ion-nav>'
})
export class SomeApp {
  @ViewChild('rootNavController') nav:NavController;

  constructor(platform: Platform) {
    this.root = RootPage;

    platform.ready().then(() => {
      // Do any necessary cordova or native calls here now that the platform is ready

      // Handle Android's back button
      // https://cordova.apache.org/docs/en/latest/cordova/events/events.backbutton.html
      // This handler might be redundant and/or undesired with future versions of Ionic 2:
      // https://github.com/driftyco/ionic/issues/5071
      document.addEventListener('backbutton', () => {
        let activeVC = this.nav.getActive();
        let page = activeVC.instance;

        if (!(page instanceof TabsPage)) {
          if (!this.nav.canGoBack()) {
            console.log('Exiting app due to back button press at the root view');
            return navigator.app.exitApp();
          }
          console.log('Detected a back button press outside of tabs page - popping a view from the root navigation stack');
          return this.nav.pop();
        }

        let tabs = page.tabs;
        let activeNav = tabs.getSelected();

        if (!activeNav.canGoBack()) {
          console.log('Exiting app due to back button press at the bottom of current tab\'s navigation stack');
          return navigator.app.exitApp();
        }

        console.log('Detected a back button press - popping a view from the current tab\'s navigation stack');
        return activeNav.pop();

      }, false);
    });
  }
}

tabs.js

import {ViewChild} from 'angular2/core';
...
export class TabsPage {
  @ViewChild('mainTabs') tabs:Tabs;
...

tabs.html

<ion-tabs #mainTabs>
...

@brandyscarney
Copy link
Member

This should've been in beta.4 but I guess we created a new issue for it. Closed the other issue as a dup.

@martijnlutgens
Copy link

I tried the workaround from tomsun, but that didn't work out for me. This did for the moment:

document.addEventListener('backbutton', () => {
let nav = this.app.getComponent('nav');
if (!nav.canGoBack()) {
return navigator.app.exitApp();
}
return nav.pop();
}, false);

@ihadeed
Copy link
Contributor

ihadeed commented Mar 6, 2016

@brandyscarney I was excited when I thought it's coming in beta.3 😞

@daveshirman
Copy link

The workaround proposed above by @tomsun is a great idea. Thanks.

@mnasyrov
Copy link

I slightly modified the workaround of @tomsun to close modals. Hope it will be helpful.

app.js, 'backbutton' handler

document.addEventListener('backbutton', () => {
  let activeNav = this.nav;

  const activeView = activeNav.getActive();
  if (activeView) {
      if (!activeView.isRoot()) {
          return activeView.dismiss();
      }
      const page = activeView.instance;
      if (page instanceof TabsPage && page.tabs) {
          activeNav = page.tabs.getSelected();
      }
  }

  if (activeNav.canGoBack()) {
      // Detected a back button press outside of tabs page - popping a view from a navigation stack.
      return activeNav.pop();
  }
  // Exiting app due to back button press at the root view
  return navigator.app.exitApp();
}, false);

@dylanvdmerwe
Copy link
Contributor

I'm hoping this will also include the newly added Windows Phone platform as well.

@brandyscarney brandyscarney changed the title Implement Android hardware back button functions Implement platform hardware back button functions Mar 21, 2016
@guillenotfound
Copy link
Contributor

The workaround seems to stop working on beta.4

The line: @ViewChild('rootNavController') nav:NavController;
Also: @ViewChild('mainTabs') tabs:Tabs;
gives me an Unexpected token in that line, any advice?

@SP1966
Copy link

SP1966 commented Apr 30, 2016

I'm on beta.6 and the back button is mostly working great. If your navigation stack has a page to go back to then the hardware back button does take you there. On the other hand, if you're at a root page then hitting the back button closes the app. I think it would be better if on root pages, rather than exiting the app it did nothing at all, or prompt the user to close the app or not. My preference would be for the back button to be non-functional on root pages.

@vukasin-nikodijevic
Copy link

@SP1966 - yep my issue is exactly what you've describe.

I vote for 2 options:

  1. Do nothing on root pages
  2. Introduce some kind of setRoot pages historical stack and if you hit backButton on root page it should return you to previous root page. If you hit backButton on rootPage with index 0 in that new stack - then close app.

@svc-user
Copy link

@SP1966 Normal behavior on Android is that the app will close if you can't pop any more activities and hit back. And so do I think ionic should work as well. If you have a different need the behavior can be overridden.

@daveshirman
Copy link

That's exactly the workaround I made. So when you're on a root page down
the menu, it goes up to index zero before the quit routine happens.

http://www.codingandclimbing.co.uk/blog/ionic-2-android-back-button-13

Although this is now kinda broken as of beta 6...

Just food for thought!
On 30 Apr 2016 8:48 p.m., "vukasin0" notifications@github.com wrote:

@SP1966 https://github.com/SP1966 - yep my issue is exactly what you've
describe.

I vote for 2 options:

  1. Do nothing on root pages
  2. Introduce some kind of setRoot pages historical stack and if you hit
    backButton on root page it should return you to previous root page. If you
    hit backButton on rootPage with index 0 in that new stack - then close app.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#5071 (comment)

@hlehmann
Copy link

By default we can keep ionic closing the app. But we should be able to easily override default behavior.

@dylanvdmerwe
Copy link
Contributor

  1. Default Android behaviour when the back button is pressed is to end the current activity. If there are no activities on the back stack, then the current activity closing will close the app.
  2. Ionic has implemented this behaviour correctly.
  3. A seperate issue should be logged for a feature request in order to override the back button logic if not already available.

See here for more information or read up on why overriding standard user interactions is a Bad Idea in mobile apps.

@mnasyrov
Copy link

It seems like a current implementation of a back button (beta.6) does not take into account a case when an active tab has its own non-empty ViewController (opened a page or a modal). For this case an aplication is closed after pressing a back button, however it is more expected to close an active tab's child page or a modal.

@vukasin-nikodijevic
Copy link

@mnasyrov - oooo yeah :)

+1

@fer-ri
Copy link

fer-ri commented May 18, 2016

any update?

@brandyscarney
Copy link
Member

There is a separate issue open for controlling the behavior of the back button: #6556

If you have any feedback for controlling the behavior please place it on that issue. If you believe there is a bug with the current implementation please create a new issue. Thanks!

@mnasyrov
Copy link

Created #6574 about closing tab's pages and modals.

@domzinhuu
Copy link

@SP1966 your back button work on beta 6? i'm in android and a cannot make this work. Please what you did?

@GaneshPediredla
Copy link

How to implement a hardware back button functionality for android in ionic2?

@domzinhuu
Copy link

Well.. i have this method on the platform.ready();
registerBackButtonListener
and the method registerBackButtonListener

registerBackButtonListener() { document.addEventListener('backbutton', () => { var nav = this.getNav(); if (nav.canGoBack()) { nav.pop(); } else { this.confirmExitApp(nav); } }); } - See more at: http://www.codingandclimbing.co.uk/blog/ionic-2-android-back-button-13#comment-2690874526
i get error in this.getNav();
getNav() { return this.app.getComponent('nav'); }

the app is null, in my constructor i try;

constructor(platform,events,app) { this.app = app; }
and import the App from ionic-angular.

but dont work :(.

this is the Dave Shirman workaround : http://www.codingandclimbing.co.uk/blog/ionic-2-android-back-button-13#comment-2690874526

@daveshirman
Copy link

I think that getComponent is gone as of beta 7. Check the Ionic blog post
for the breaking changes, this is mentioned.
On 23 May 2016 5:15 p.m., "Maique Rosa" notifications@github.com wrote:

Well.. i have this method on the platform.ready();

registerBackButtonListener

and the method registerBackButtonListener

registerBackButtonListener() { document.addEventListener('backbutton', ()
=> { var nav = this.getNav(); if (nav.canGoBack()) { nav.pop(); } else {
this.confirmExitApp(nav); } }); } - See more at:
http://www.codingandclimbing.co.uk/blog/ionic-2-android-back-button-13#comment-2690874526

i get error in this.getNav();

getNav() { return this.app.getComponent('nav'); }

the app is null, in my constructor i try;

constructor(platform,events,app) {
this.app = app;
}

and import the App from ionic-angular.

but dont work :(.

this is the Dave Shirman workaround :
http://www.codingandclimbing.co.uk/blog/ionic-2-android-back-button-13#comment-2690874526


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#5071 (comment)

@domzinhuu
Copy link

Ok

@fer-ri
Copy link

fer-ri commented May 26, 2016

on Beta 7, app always close when hit back button even we put return false; or this.nav.pop()

any idea?

Thanks

@shprink
Copy link

shprink commented May 29, 2016

In Beta7 the app still exits when a modal is opened and we hit back button. Should we reopen that?

@xelamak
Copy link

xelamak commented Jun 7, 2016

I think this should be open, currently cannot stop the back button from closing the app without displaying any prompt. Perhaps there is a way to override the default back button handler but yet to be documented?

@fer-ri
Copy link

fer-ri commented Jun 7, 2016

For now, you can comment these lines on node_modules/ionic-angular/components/app/app.js around line 31

        // platform.backButton.subscribe(function () {
        //     var activeNav = _this.getActiveNav();
        //     if (activeNav) {
        //         if (activeNav.length() === 1) {
        //             platform.exitApp();
        //         }
        //         else {
        //             activeNav.pop();
        //         }
        //     }
        // });

Now you can doing something like this from app.ts

this.platform.backButton.subscribe(() => {
            this.menu.close();

            if (this.nav.canGoBack()) {
                this.nav.pop();

                return;
            }

            let activePage = this.nav.getActive().instance;

            let whitelistPages = [AuthPage, DashboardPage];

            // if current page is not in whitelistPage
            // then back to DashboardPage first
            if (whitelistPages.indexOf(activePage.constructor) < 0) {
                this.nav.setRoot(DashboardPage);

                return;
            }

            if (! this.backPressed) {
                this.backPressed = true

                showToast('Press again to exit', 2000);

                setTimeout(() => this.backPressed = false, 2000)

                return;
            }

            this.platform.exitApp();
        }, error => showToast(error))

For sample app you can download from https://play.google.com/store/apps/details?id=com.ferrisutanto.ezygriya

You need to press back button twice under 2000ms to exit app ..

@xelamak
Copy link

xelamak commented Jun 7, 2016

Thank you @ghprod , your method works for now. I am still suggest to open the issue for making the default back button handler be able to be overridden. There would be a lot of ways to do so, like allowing the handler function be passed by the config during bootstrap, only use the default one when such does not presents. Despite exposing the subscriber via getter (e.g. getBackButtonHandler()) which will allow us to unsubscribe it with getBackButtonHandler().unsubscribe() and then subscribe our own handler.

@fer-ri
Copy link

fer-ri commented Jun 7, 2016

Yes, agree with you .. 👍

@Vasanth19
Copy link

Vasanth19 commented Jul 2, 2016

@shprink I have the same issue, if i hit the back button when the modal is open, the app exits even before executing the this.platform.backButton.subscribe(...,
any solution for this?

@mhartington Any suggestions? i am using beta.7

@vedantshirke
Copy link

Hello,

I'm using ionic version 2.0.0 when i press the back button it closes the app. I have something like this to perform an event on click of back button

$ionicPlatform.onHardwareBackButton(callToAFunction);

But this is not working instead of calling the function it closes the app.

Any suggestions?
Thanks.

@zakrava
Copy link

zakrava commented Dec 18, 2016

I found cordova-plugin-backbutton for that.

@dylanvdmerwe
Copy link
Contributor

@mhartington can this be closed? Should have been resolved here #8692

@zakrava
Copy link

zakrava commented Dec 18, 2016

There is missing ts binding in ionic 2 for navigator.app.overrideButton() cordova function.

@xiaosan666
Copy link

https://github.com/yanxiaojun617/ionic2_tabs
or
http://www.jianshu.com/p/6aa5a8318092

@ionitron-bot
Copy link

ionitron-bot bot commented Sep 5, 2018

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Sep 5, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests