Simple Ionic Tabs App with Child Routes & Protected Routes

Aaron K Saunders - Jul 11 '19 - - Dev Community

Two question I often see posted about Ionic apps are
1) how do I handle authentication ( protected routes ) and
2) How do I handle child routes when using Tabs in Ionic.

So I am going to try to present a simple bare bones solution that addresses both problems with the code I have below. I have only included the code snippets that are essential to address the issues listed above, but the complete source code is available here: ionicv4-tabs-with-detail

This example code is based on v4 of Ionic Framework

Protected Routes

To have protected routes you need to be able to determine the logged in state of the user. To keep things as simple as possible, we have created an AuthenticationService that has a method to set the state as true or false and a method to get the current logged in state.

@Injectable({
    providedIn: "root"
})
export class AuthenticationService {
    isLoggedIn = false;

    constructor() { }

    setLoggedIn(_value) {
        this.isLoggedIn = _value;
    }
    isAuthenticated(): boolean {
        return this.isLoggedIn;
    }
}
Enter fullscreen mode Exit fullscreen mode

Next we create a new class AuthGuardService which implements the CanActivate interface.

In this example, all we are doing is calling the AuthenticationService to see if the user is authenticate or not, if the used is not authenticated, then we are redirecting the user to the route defined by the path /login. We are doing that by constructing a UrlTree object and returning that since we can return a boolean, Promise or UrlTree from the function according to the CanActivate documentation

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRoute, Router } from '@angular/router';
import { AuthenticationService } from './authentication.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuardService implements CanActivate {

  constructor(private auth: AuthenticationService, private router: Router) { }

  canActivate(): boolean {
    let value = this.auth.isAuthenticated()
    if (!value) {
      // initially was just redirecting here, but following the
      // documentation I updated code to return a UrlTree
      // this.router.navigateByUrl("/login", { skipLocationChange: true })

      return this.router.parseUrl("/login");
    }
    return value
  }
}
Enter fullscreen mode Exit fullscreen mode

Now that we have our AuthenticationService to tell us the state of the user, our AuthGuardService to be used to check before rendering a route; we are ready to update the app-routing.module.

See below where we add the AuthGuardService to the default route so that when the app is first launched, the users authentication state will be verified, otherwise it will redirect to the LoginPageModule

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuardService } from '../services/authGuard.service';

// in the routes that need to be protected or the user
// has to be authenticated, we add the AuthGuardService
const routes: Routes = [
  { 
    path: '', 
    canActivate: [AuthGuardService], 
    loadChildren: './tabs/tabs.module#TabsPageModule' 
  },
  { 
    path: 'login', 
    loadChildren: './public/auth/login/login.module#LoginPageModule' 
  },
];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
Enter fullscreen mode Exit fullscreen mode

Child Routes In Tabs

The tabs router module has some magic here to handle the default route and also to properly handle child routes to properly manage the navigation stack for each tab.

The first component rendered is the TabsPage, but as you can see that page has child modules, the first one being the HomePageModule which will render the HomePage.

(1) at the bottom of the code segment below we show how we handle the default route for the tab module, redirecting it to the home tab.

Handling the child route of a tab, or rendering a detail page is demonstrated with the second route definition under the home path. We have defined the path detail which we access using the full path of /tabs/home/detail

(2) This will load the DetailPageModule which will in turn load the DetailPage since it is the default route in the DetailPageModule.

const routes: Routes = [
  {
    path: "tabs",
    component: TabsPage,
    children: [
      {
        path: "home",
        children: [
          {
            path: "",
            loadChildren: "./../home/home.module#HomePageModule"
          },
          // (2) loads detail page, pushing it on the navigation stack of 
          // the home tab
          {
            path: "detail",
            loadChildren: "./../detail/detail.module#DetailPageModule"
          }
        ]
      },
      {
        path: "about",
        children: [
          {
            path: "",
            loadChildren: "./../about/about.module#AboutPageModule"
          }
        ]
      },
      {
        path: "contact",
        children: [
          {
            path: "",
            loadChildren: "./../contact/contact.module#ContactPageModule"
          }
        ]
      }
    ]
  },
  // (1) the default route of this module is the home tab so that tab is
  // displayed when directed here from the top level router module.
  {
    path: "",
    redirectTo: "/tabs/home",
    pathMatch: "full"
  }
];
Enter fullscreen mode Exit fullscreen mode

Handling the Routes in the Application

Log In

For logging in to the application, we have included the following code in the login.page.ts file. The application will first call the injected AuthenticationService to set the logged in state, and then it will navigate to the default route of the application

  login() {
    this.auth.setLoggedIn(true)
    this.router.navigateByUrl("/", { skipLocationChange: true });
  }
Enter fullscreen mode Exit fullscreen mode

Log Out

For logging out of the application, we have included the following code in the home.page.ts file. The application will first call the injected AuthenticationService to set the logged in state, and then it will navigate to the login route of the application.

  logout() {
    this.auth.setLoggedIn(false)
    this.router.navigateByUrl("/login", { skipLocationChange: true });
  }
Enter fullscreen mode Exit fullscreen mode

Detail Page

For navigating the child root from the HomePage Tab, we have included the following code in the page; using an ion-button

<ion-button routerLink="/tabs/home/detail">Next</ion-button>
Enter fullscreen mode Exit fullscreen mode

Project Source Code

For the sake of brevity, I have not included all of source code this post, but the git hub repo is listed below.

GitHub logo aaronksaunders / ionicv4-tabs-with-detail

Simple Ionic Tabs App with Child Routes & Protected Routes






Even More...

Here is a similar implementation, but it includes the sidemenu/splitpane along with the Tabs and authentication

GitHub logo aaronksaunders / ionic4-sidemenu-auth

Building a Basic Ionic 4 Login Flow with Angular Router & Side Menu UI

ionic4-sidemenu-auth

Building a Basic Ionic 4 Login Flow with Angular Router & Side Menu UI ( now with Tabs !! )

Updated to latest Ionic Versions

Ionic:

   Ionic CLI                     : 5.4.13 (/Users/aaronksaunders/.nvm/versions/node/v10.15.1/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.11.7
   @angular-devkit/build-angular : 0.803.21
   @angular-devkit/schematics    : 8.1.3
   @angular/cli                  : 8.1.3
   @ionic/angular-toolkit        : 2.1.1

Utility:

   cordova-res                          : not installed
   native-run (update available: 0.3.0) : 0.2.9

System:

   NodeJS : v10.15.1 (/Users/aaronksaunders/.nvm/versions/node/v10.15.1/bin/node)
   npm    : 6.11.2
   OS     : macOS Catalina
  • Code recently updated to latest version of Ionic "@ionic/angular": "^4.3.0",
  • Made it a bit more complex with
    • Authentication
    • Side Menu
    • Tabs
    • Tab Detail Page
  • based on great work done here - https://devdactic.com/ionic-4-login-angular/

How It Works

We put an AuthGuard on the module that provides access to all of the member related pages and functionality. The login page has no gaurd so it can be freely accessed. See more information on Route Guards in the angular.io documentation

const routes
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .