Skip to content

servrox/demo-ionic-tabs-back-button

Repository files navigation

Demo: Ionic tabs + global pages with ion-back-button

Ionic 4 project with a tab based layout and workarounds for the ion-back-button.
The demo shows two ways how to navigate from a tabbed page to a 'global' page and back,
without losing tab-states.

Live Demo

Getting Started

git clone https://github.com/servrox/demo-ionic-tabs-back-button.git
cd demo-ionic-tabs-back-button
yarn
ionic serve

Solutions shown in demo

First solution is a workaround that overcomes the problem.
The second one is a fix which deals directly with the problem
by using ion-back-button-tabs a custom ionic 4 component.

1. Passing previous page (s. global-page-one)

This solution overcomes the problem by using an ion-button instead of the ion-back button.
To make it work following steps are necessary:

  1. Get the route you want to navigate back later.
this.currentRoute = btoa(this.router.url);
  1. Pass that value to the page called. (url params used here)
<ion-button 
    [routerLink]="['/global-page-one', {p: currentRoute}]"
    routerDirection="forward">
    Global Page One
</ion-button>
  1. On the page called check if a route was given
this.previousPage = this.route.snapshot.paramMap.get('p') ? atob(this.route.snapshot.paramMap.get('p')) : null;
  1. Use given route when user clicks back
back() { this.navCtrl.navigateBack(this.previousPage); }

To make the ion-button look exactly like the ion-back-button, you can check which platform is being used.

this.showText = this.plt.is('ios');

If the page with the back-button is the first page called, the real ion-back-button can be used. This works because then the defaultHref is taken.

this.router.events.subscribe((event: RouterEvent) => {
    if (event instanceof NavigationEnd) { 
        this.useRealBackButton = event.id === 1; 
    }
});

Final solution looks like this in template:

<ion-buttons slot="start">
    <ion-back-button *ngIf="useRealBackButton" 
        [defaultHref]="previousPage ? previousPage : '/tabs/tab1'">
    </ion-back-button>
    <ion-button *ngIf="!useRealBackButton" (click)="back()">
        <ion-icon name="arrow-back"></ion-icon>
        {{ showText ? 'Back' : null }}
    </ion-button>
</ion-buttons>

In this solution swiping back (iOS gesture) is disabled for the particular page.

ngOnInit() { this.routerOutlet.swipeGesture = !this.plt.is('ios');
  [...]
ionViewDidLeave() { this.routerOutlet.swipeGesture = this.plt.is('ios'); }

ion-back-button-tabs supports swiping back! (see below)

2. Using ion-back-button-tabs component (s. global-page-two)

  1. Install from npm
npm i ion-back-button-tabs --save
  1. Import BackButtonTabsModule to the page module (global-page-two.module.ts)
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';

import { GlobalPageTwoPage } from './global-page-two.page';

import { BackButtonTabsModule } from 'ion-back-button-tabs';

const routes: Routes = [
  {
    path: '',
    component: GlobalPageTwoPage
  }
];

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    RouterModule.forChild(routes),
    BackButtonTabsModule
  ],
  declarations: [GlobalPageTwoPage]
})
export class GlobalPageTwoPageModule { }
  1. Get attributes for ion-back-button-tabs
  • tabsPrefix is the url path set for the TabsPage component (e.g. 'tabs')
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TabsPage } from './tabs.page';

const routes: Routes = [
  {
    path: 'tabs',
    component: TabsPage,
    children: [
      {
        path: 'tab1',
        children: [
          {
            path: '',
            loadChildren: '../tab1/tab1.module#Tab1PageModule'
          }
        ]
      },
      {
        path: 'tab2',
...
  • tabsPageSelector is the selector of the TabsPage component (e.g. 'app-tabs')
import { Component } from '@angular/core';

@Component({
  selector: 'app-tabs',
  templateUrl: 'tabs.page.html',
  styleUrls: ['tabs.page.scss']
})
export class TabsPage {}

  1. Use ion-back-button-tabs in template
<ion-back-button-tabs 
  defaultHref="/tabs/tab1" 
  tabsPrefix="tabs" 
  tabsPageSelector="app-tabs">
</ion-back-button-tabs>

Problem explained

When navigating from a page inside a tab to a 'global' page, the ion-back button will no longer work properly.
More specifically, the back button no longer navigates to the previously opened page, instead it uses the redirect of the tabs-routing.

This happens because the ion-back-button uses only the main-IonRouterOutlet, instead of also checking tabs-IonRouterOutlet.
Which means that the StackController inside the main-IonRouterOutlet only knows the route of the tabs module (e.g. 'tabs').
^No guarantee on this^

Problem is also described in the official Bug Report.

Built With

Authors