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;
}
}
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
}
}
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 { }
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"
}
];
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 });
}
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 });
}
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>
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.
aaronksaunders / ionicv4-tabs-with-detail
Simple Ionic Tabs App with Child Routes & Protected Routes
ionicv4-tabs-with-detail
- Updated to latest version
- addressed issue with icons not showing up
- addressed issue with bad animation to nested page
See Another Ionic v4 Example
https://github.com/aaronksaunders/ionic4-sidemenu-auth
Blog Post
https://dev.to/aaronksaunders/simple-ionic-tabs-app-with-child-routes-protected-routes-1k24
Even More...
Here is a similar implementation, but it includes the sidemenu/splitpane along with the Tabs and authentication
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
…
Top comments (1)
I've been struggling with nested routes in the tabs for days. Thank you for this post, Aaron!