developers

Ionic 4 Beta: What’s New and Building a Sample App

Learn what is coming next on Ionic 4 and start using it right now.

Oct 11, 201828 min read

TL;DR: In this article, you will learn about what's new in Ionic 4, changes in the existing features, how to migrate your Ionic 3 app to Ionic 4 app, and about using Ionic with Stencil and Capacitor. Finally, you will create a simple application using Ionic 4 to see the new version of this framework in action. If you need, you can check the final code of the app that you will create on this GitHub repository.

Learn about what's new in Ionic 4, changes in the existing features, how to migrate your Ionic 3 app to Ionic 4 app, and about using Ionic with Stencil and Capacitor.

Tweet This

Ionic 4 Beta: Learn What's New

The Ionic framework is quite a famous name in the mobile application development area. Ever since this framework came into existence, it's been tightly coupled to Angular. For example, Ionic 1 was built on Angularjs, and Ionic 2 and Ionic 3 are based on Angular2+.

Starting with Ionic 4, things are now different. Ionic components are now built using Web Components with the help of Stencil. What is interesting about Web Components is that you can use them with any framework or even without a framework. That makes it possible to use Ionic with Angular, React, Vue, or whatever other frameworks you can imagine.

Right now, the new (but still beta) version 4 of Ionic is available via the

@ionic/core
NPM package. Also, there are Angular bindings available via the
@ionic/angular
NPM package
. Alongside with that, the official bindings for React and Vue are currently in development.

This article will mostly focus on

@ionic/angular
. Here, you will learn how to create new Ionic/Angular applications, make navigation, migrate Ionic3 app to Ionic4 app, and you will also create a demo application using Ionic/Angular.

Ionic 4 and Angular

In this section, you will read about the changes that Ionic 4 brought with respect to Angular. In other words, you will be learning about the changes in

@ionic/angular@v4
.

Routing in Ionic 4 and Angular

One of the biggest changes in Ionic 4 is the support of Angular Router. With Ionic 4, you can use

@angular/router
to handle the navigation of your Ionic apps. However, keep in mind that Ionic 4 still supports the Push/Pop
ion-nav
navigation system.

In a typical Angular application, you have to use

router-outlet
component to project the view. In Ionic 4 applications, you will use a version of
router-outlet
called as
ion-router-outlet
. Basically, you have to add following HTML element in the template where you want to project the view.

<ion-router-outlet></ion-router-outlet>

After adding the

ion-router-outlet
component, you will need to create a router config, which is required to configure the navigation paths of your Angular application. This can be done as follows:

let routes:Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home',loadChildren:'./pages/home/home.module#HomePageModule' },
  { path: 'user/:id', loadChildren: './pages/user/user.module#UserPageModule' },
  { path: '**', redirectTo: 'home', pathMatch: 'full'},
]

Angular Router parses the router config from top to bottom. The above config basically conveys the follows:

  • If users navigate to the
    /
    route, then your app will redirect them the
    /home
    route.
  • If users navigate to
    /home
    route, then your app will load the
    HomePageModule
    .
  • If users navigate to
    /user/:id
    route, then your app will load the
    UserPageModule
    . In this case,
    :id
    is a navigation parameter. For example: if users try to reach
    /users/u101
    ,
    u101
    is the value
    :id
    will get.
  • If users open any route which doesn't match any path in your config, your app will redirect them to
    /home
    .

Note: the

loadChildren
property in a route is used for Lazily Loading an Angular Module. By default, if you generate a page using Ionic CLI, it will be lazily loaded.

Then you have to provide these routes to the

RouterModule
in the root
@NgModule
of your Angular application, as follows:

// your imports here

@NgModule({
  ...
  imports: [
    ...
    RouterModule.forRoot(routes);
  ]
})

Now, when your Angular application bootstraps, it will load the default route specified in your Router configuration. But the rest of the navigation will depend upon users' interaction with the app per se. To trigger navigation, you two options: one is declarative, and the other one is imperative.

For example, to define a declarative navigaiton in your Angular application, you can use the

routerLink
directive:

<a routerLink="/home">Home</a>

With that, if your users click on the above anchor element, the app will trigger navigation to the

/home
route. If you come from previous versions of the Ionic framework, you will probably remember that you used to have nice animation flows that appeared when you were pushing a new view or page to your users. This is still possible by using
routerDirection
directive along with
routerLink
.

Basically, there are three possible values for this directive:

  • forward
    : It's just like pushing a view to the navigation stack.
  • backward
    : It's like popping a view from the navigation stack.
  • root
    : It behaves like
    setRoot
    method of NavController. This means that it will make the page that you are about to navigate to the root page of the application.

For example, to use the

forward
option you could have something like this:

<a routerLink="/home" routerDirection="forward">Home<a>

Now, when it comes to define imperative navigation in your app, you can call the

navigateForward
,
navigateBack
, and
navigateRoot
methods of
NavController
:

// similar to routerDirection="forward"
this.navCtrl.navigateForward('/user/u101');

// similar to routerDirection="backward"
this.navCtrl.navigateBack('/home');

// similar to routerDirection="root"
this.navCtrl.navigateRoot('/home');

Using Ionic and Angular CLI

With Ionic 4, Ionic CLI projects are almost similar to Angular CLI projects. As a matter of fact, Ionic CLI uses Angular CLI internally.

To use the latest Ionic CLI version, make sure you install it:

npm install -g ionic

Next step, if you were going to create a new app, you would issue commands with starter templates as below (don't really worry about running this now, you will soon create your app):

ionic start myApp blank --type=angular

Note:

--type=angular
tells Ionic CLI to generate an Angular-based project.

When you scaffold your app, you will get a file structure that looks like the following:

  • e2e
    : This is a directory that contains default end-to-end test code and where you can write your own tests.
  • resources
    : This is a directory that contains resources like icons and images for your mobile app.
  • src
    : This is where you will put the source code of your Ionic application.
  • angular.json
    : A file that contains all the configuration of your project. You can configure your
    production
    or
    dev
    environment and lots of the other things. This file makes it possible to use Angular CLI with Ionic projects.
  • config.xml
    : The config file for Cordova.
  • ionic.config.json
    : The config file used by Ionic CLI.
  • tsconfig.json
    : The config file that defines rules for the TypeScript compiler.
  • tslint.json
    : The config file that defines rules for the TypeScript linter.

Just like with Angular CLI, after scaffolding your app, you will be able to run a hello-world app by issuing a single command:

ionic serve

Theming in Ionic 4

With Ionic 4, the Ionic team is adopting web standards. In the new version of the framework, all of the Ionic Components are built using Stencil (which means that they are relying on the Web Component spec). With respect to theming, Ionic is using CSS variables.

By default, Ionic comes with nine colors, and each one of these has two extra variants called as shade and tint. You can easily edit the default color values along with their shade and tint variant.

Color Structure

Before you start modifying existing colors in Ionic, you need to understand some concepts. Each default color in Ionic has multiple properties, kind of like having multiple layers of colors. Each of these properties is applied to a different part of a particular component. These properties are as follows:

  • base
    : The main color that will be applied to the component.
  • shade
    : A bit darker than the base color and used to add shades.
  • tint
    : It's a bit lighter than the base color.
  • contrast
    : Contrast color is a color which is easily visible (perceptible) on the base color. For example, if the base is black, then contrast would be white. Basically, contrast is used for showing text on components like button, list, etc.

Following is an excerpt of the default primary color values from an Ionic project:

:root {
  --ion-color-primary: #488aff;
  --ion-color-primary-rgb: 72,138,255;
  --ion-color-primary-contrast: #fff;
  --ion-color-primary-contrast-rgb: 255,255,255;
  --ion-color-primary-shade: #3f79e0;
  --ion-color-primary-tint: #5a96ff;
}

Modifying Existing Color

When you open the

/src/theme/variable.scss
file, you can see all nine default colors in that file. You can modify any of the values as shown below:

:root {
  --ion-color-primary: #00ff00;
  --ion-color-primary-shade: #00fff0;
  --ion-color-primary-tint: #00fa00;
}

Above example changes the primary color (along with it's

shade
and
tint
properties) to
#00ff00
for the whole application. You can also change this particular color for a particular component as follows:

.my-button {
  --ion-color-primary: #00ff00;
}

Migrating from Ionic 3 to Ionic 4

Migration is always a difficult and painful subject. However, the team behind the Ionic framework worked hard to make things as easy as possible. The following list presents some tasks that you will have to do to migrate from Ionic 3 to Ionic 4:

  • Angular Router: As mentioned earlier, you need to migrate your Push/Pop navigation to Angular Router navigation. You can follow the step mentioned above to do so.
  • NavParams Service: With Angular Router, you can't use the beloved
    NavParams
    service, but there are many alternatives to it. One of the best would be using NgRx to manage the state. It's fairly easy to use NgRx to mimic the same behavior of the
    NavParams
    service. However, there is a file inside Ionic 4's GitHub repo which might be hinting at
    NavParams
    debut in Ionic 4.
  • LifeCycleEvents: Since you will not use the
    ion-nav
    navigation element, you can't use
    ionViewWillLoad
    or similar life cycle events. However, you can use Angular's life cycle hooks in their place. To learn more about Angular lifecycle hooks, take a look here.
  • Markup: There are lots of changes in markup due to the fact that Ionic uses the Web component spec. It's out of scope of this blog post to talk about all those changes. Nevertheless, it is important to notice that the Ionic team introduced a migration linter for markup that you can use.

Using the Migration Linter

It's definitely fun to learn things and sometimes you need to change things manually. But if at a certain point you can do things automatically, you should opt for it. As mentioned, the Ionic team also introduced a migration linter tool that you can use to migrate your Ionic 3 markup to Ionic 4 markup.

To use it, you will have to install the lint rules:

npm i -D @ionic/v4-migration-tslint

Then you will need to create a file called

ionic-migration.json
at the root of your project and paste in the following JSON:

{
  "rulesDirectory": ["@ionic/v4-migration-tslint/rules"],
  "rules": {
    "ion-action-sheet-method-create-parameters-renamed": true,
    "ion-alert-method-create-parameters-renamed": true,
    "ion-datetime-capitalization-changed": true,
    "ion-item-option-method-get-sliding-percent-renamed": true,
    "ion-overlay-method-create-should-use-await": true,
    "ion-overlay-method-present-should-use-await": true,
    "ion-back-button-not-added-by-default": { "options": [true], "severity": "warning" },
    "ion-button-attributes-renamed": true,
    "ion-button-is-now-an-element": true,
    "ion-chip-markup-has-changed": true,
    "ion-fab-button-is-now-an-element": true,
    "ion-fab-attributes-renamed": true,
    "ion-fab-fixed-content": true,
    "ion-col-attributes-renamed": true,
    "ion-icon-attribute-is-active-removed": true,
    "ion-item-is-now-an-element": true,
    "ion-item-ion-label-required": true,
    "ion-item-attributes-renamed": true,
    "ion-item-divider-ion-label-required": true,
    "ion-item-options-attribute-values-renamed": true,
    "ion-item-option-is-now-an-element": true,
    "ion-label-attributes-renamed": true,
    "ion-list-header-ion-label-required": true,
    "ion-menu-toggle-is-now-an-element": true,
    "ion-navbar-is-now-ion-toolbar": true,
    "ion-option-is-now-ion-select-option": true,
    "ion-radio-attributes-renamed": true,
    "ion-radio-slot-required": true,
    "ion-radio-group-is-now-an-element": true,
    "ion-range-attributes-renamed": true,
    "ion-spinner-attribute-values-renamed": true,
    "ion-tab-attributes-renamed": true,
    "ion-text-is-now-an-element": true,
    "ion-buttons-attributes-renamed": true
  }
}

Then you can lint your project by running the following command:

npx tslint -c ionic-migration.json -p tsconfig.json

Ionic 4 will have tools to help you migrate your code automatically.

Tweet This

Note :

npx
is a new utility that comes with NPM
v5.2.0
. This tool allows you to run local Node executables from the
node_modules
directory.

Ionic 4 and Stencil

Before you start digging into this section, you should learn a few things about Stencil. Basically speaking, Stencil is a compiler that lets you create UI Components and Web Apps using the Web Component specification. Coding with Stencil is kind of like a mixture of Angular and React. While developing with Stencil, you will use Decorators, JSX, and TypeScript to name a few.

A typical Stencil Component looks like follows:

import { Component, Prop } from '@stencil/core';

@Component({
  tag: 'name-component',
  styleUrl: 'name-component.scss'
})
export class NameComponent {
  @Prop() name: string;

  render() {
    return (
      <p>
        Welcome, {this.name}
      </p>
    );
  }
}

Then, to use your new web component, you can just add it to your HTML like any other element:

<name-componet name="Indermohan Singh"></name-component>

Using Ionic with Stencil

You might be wondering, why would I want to read about Stencil in an Ionic article? In other words, how would you benefit from learning about Ionic and Stencil?

The best answer to that question is that Ionic Core is built using the Stencil compiler. That is, they play really nicely with each other. Moreover, Stencil has enough plug-ins that you can use to write a complete application. Also, Stencil comes with an Ionic PWA (Progressive Web App) starter that can be used to create Ionic applications.

As you will see here, it's fairly easy to get started with Ionic and Stencil. To do so, you will need to run the following command to trigger Stencil CLI:

npm init stencil

This command will ask you questions like:

  1. Pick a starter: First, it will ask you to pick a starter. There is three starters for now:
    ionic-pwa
    , which is Ionic with the PWA toolkit;
    app
    , a minimal starter to build stencil app or website; and
    component
    , a collection of web components to test the PWA capabilities, select the
    ionic-pwa
    option.
  2. Project name: For this, you can add any name that you can come up with.
  3. Confirm?: Finally, it will ask you to confirm. Press y to confirm.

Now you can run the application as follows:

npm run start

To build the application, you can run the following command:

npm run build

The above command will generate a

www
directory with all the files required to deploy or build a mobile application using Capacitor or Cordova.

Using Stencil Plugins with Ionic 4

With Ionic, there are some plug-ins available to do certain things, for example:

  • @stencil/router
    : This is a router plugin for stencil applications that can be used to manage routing in your apps.
  • @stencil/redux
    : If you like managing the state of your apps with Redux style, you can do that via this package.

Furthermore, you can use any JavaScript library with Stencil applications, because Stencil components transpile into plain JavaScript web components.

Building Mobile Apps with Capacitor on Ionic 4

Capacitor is the latest kid on the block when it comes to hybrid app development. What is impressive about Capacitor is that you can literally drop it inside any JavaScript project.

Capacitor is a new tool doing the same thing (like Cordova for example) with a different API for creating plugins. But in the end, both things are running your application inside a web view (i.e., an embedded browser instead of a real native app).

Capacitor supports Cordova Plugin. So it's easy to migrate your Cordova application to Capacitor application. To add Capacitor into your front-end application, you can simply go to some app that you have and run the following command:

npm install --save @capacitor/core @capacitor/cli

After installing it, you will have to initialize Capacitor by running this:

npx cap init

Then, you need to add the platform for which you want to build the application. For example, to configure your project to run on Android, you can issue the following command:

npx cap add android

Finally, you need to open the project and

run
or
build
it via platform's provide IDE. Run the following command to open Android Studio:

npx cap open android

After that, you can use respective platform features to build or run the application.

Note: It's also worth mentioning that you can combine Ionic, Stencil, and Capacitor to create a mobile application. Just follow the above instructions inside your Stencil Ionic PWA app, and you are good to go.

Ionic 4 In Action

In this section, you are going to create a very simple IonicaApplication with a couple of pages. What will be interesting about this app is that some of the content will be publicly available (that is, no authenticated is required) and some are for authenticated users only.

The application that you will build is similar to a contact directory. The first page will have a list of people with their names and avatar picture. Then, when users click on contact, the app will show the details of the contact clicked.

Start building Ionic 4 apps right now!

Tweet This

Creating an Auth0 Account

Before you move on and start developing the application, you will need to sign up to Auth0. The idea of using Auth0 is to leverage some state-of-the-art functionality that will give you enough power (and confidence) to focus on what matters the most, your app details. As such, the first thing you will do is to sign up for a free Auth0 account here .

After signing up to your Auth0 account, you will need to create an Auth0 Application to represent your new app. So, move to the Applications page in your Auth0 dashboard and click on Create Application. After clicking on it, Auth0 will show a dialog where you will have to type the name of your application (e.g., "Ionic 4 In Action") and you will have to select the type of application (in this case, you will have to choose Native App). Then, you can press the Create button.

Clicking on this button will redirect you to the configuration details of your app. In this page, you will have to add the following values to the Allowed Web Origins box:

http://localhost:8100

This makes Auth0 accept requests from this URLs. Alongside with that, you will also need to configure the callback URL for the application:

http://localhost:8100/callback

This is the URL that Auth0 will call after users authenticate.

Scaffolding the Ionic Application

First, you need to have the latest Ionic CLI installed, as mentioned earlier. If you haven't done so yet, run the following command:

npm install -g ionic

Now, run the following command to create a new blank project and to move into the project folder:

# scaffold your new app
ionic start ionic-4-demo blank --type=angular

# move into it
cd ionic-4-demo

The first command will ask you a couple of questions:

  • Integrate your new app with Cordova to target native iOS and Android? (y/N): Press Y
  • Install the free Ionic Pro SDK and connect your app? (Y/n): Press N

Inside your new project, issue the following command to install the

auth0-js
library:

npm install --save auth0-js

Also install a CSS library to show some country flags, as follows:

npm install --save flag-icon-css

After that, run the default app using Ionic CLI:

ionic serve

CLI will spin-up the web server and open this app in your default browser. If you take a closer look, you will see that Ionic CLI under the hood is using Angular CLI to run this app.

Initializing an Ionic 4 app

Creating a Service for your Data

Now that you have scaffolded your Ionic app, you will create a service called

DataService
to fetch dummy data to your app. To create this service, run the following command from the project root:

ionic g service services/data/data

This will generate a couple of files in the

./src/app/services/data
directory. Now, open the
data.service.ts
file and replace its content with the following:

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {of as observableOf} from 'rxjs';
import {map, tap} from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  people: any = [];

  constructor(private http: HttpClient) {
  }

  getPeopleList() {
    if (this.people.length) {
      return observableOf(this.people);
    } else {

      return this.http.get('https://randomuser.me/api/?results=20&?seed=foobar')
        .pipe(
          map((data: any) => data.results),
          tap(people => this.people = people),
        );
    }
  }

  getPerson(index) {
    if (!this.people[index]) {
      return this.getPeopleList()
        .pipe(
          map(people => this.people[index])
        );
    } else {
      return observableOf(this.people[index]);
    }
  }
}

As you can see, this service is using an online API called Random User Generator to load a list of dummy contacts to your app. This service contains two methods:

  1. getPeopleList
    : The method that loads the dummy data and returns a list of 20 random contacts.
  2. getPerson
    : A method that returns the details of a particular contact.

After creating this service, you will have to create another one. This other service will be responsible for handling your users' sessions and, as such, you will call it

AuthService
. To create this service, issue the following command:

ionic g service services/auth/auth

Again, this command will generate a couple of files in the

/src/app/services/auth
directory. Now, open the
auth.service.ts
file and replace its code with the following:

import {Injectable} from '@angular/core';
import {Router} from '@angular/router';
import {Subject} from 'rxjs';
import * as auth0 from 'auth0-js';

(window as any).global = window;

@Injectable()
export class AuthService {
  isLoggedIn$ = new Subject();
  isLoggedIn: Boolean = false;
  auth0 = new auth0.WebAuth({
    clientID: 'YOUR_CLIENT_ID',
    domain: 'YOUR_AUTH_DOMAIN',
    responseType: 'token id_token',
    audience: 'https://YOUR_AUTH_DOMAIN/userinfo',
    redirectUri: 'http://localhost:8100/callback',
    scope: 'openid'
  });

  constructor(public router: Router) {
    // Check if user is logged In when Initializing
    const loggedIn = this.isLoggedIn = this.isAuthenticated();
    this.isLoggedIn$.next(loggedIn);
  }

  public login(): void {
    this.auth0.authorize();
  }

  public handleAuthentication(): void {
    this.auth0.parseHash((err, authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        window.location.hash = '';
        this.setSession(authResult);
        const loggedIn = this.isLoggedIn = true;
        this.isLoggedIn$.next(loggedIn);
        this.router.navigate(['/home']);
      } else if (err) {
        const loggedIn = this.isLoggedIn = false;
        this.isLoggedIn$.next(loggedIn);
        this.router.navigate(['/home']);
      }
      console.log(this.isLoggedIn);
    });
  }

  private setSession(authResult): void {
    // Set the time that the Access Token will expire at
    const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
    localStorage.setItem('access_token', authResult.accessToken);
    localStorage.setItem('id_token', authResult.idToken);
    localStorage.setItem('expires_at', expiresAt);
  }

  public logout(): void {
    // Remove tokens and expiry time from localStorage
    localStorage.removeItem('access_token');
    localStorage.removeItem('id_token');
    localStorage.removeItem('expires_at');
    // Go back to the home route
    const loggedIn = this.isLoggedIn = false;
    this.isLoggedIn$.next(loggedIn);
  }

  public isAuthenticated(): boolean {
    // Check whether the current time is past the
    // Access Token's expiry time
    const expiresAt = JSON.parse(localStorage.getItem('expires_at') || '{}');
    return new Date().getTime() < expiresAt;
  }
}

Note that, before running your app again, you will have to replace

YOUR_CLIENT_ID
and both places that show
YOUR_AUTH_DOMAIN
with your own Auth0 values. The first value, you will have to replace with the Client ID property of the Auth0 Application you created before. The second value,
YOUR_AUTH_DOMAIN
, you will have to replace with the Domain value of the same Auth0 Application.

Besides configuring your app to communicate with Auth0, this service also contains the following methods:

  • login
    : This method initiates the login process and shows an Auth0's hosted login page.
  • handleAuthentication
    : This method is called when the authentication process is finished. If the user is successfully logged in, this method calls
    this.setSession
    so it sets
    this.isloggedIn
    to
    true
    and redirect users to the
    /home
    route. If the authentication is not successful, it sets
    this.isloggedIn
    to
    false
    but also redirects to the
    /home
    route. You will have to call this method inside the root component of your application so that it can read the URL hash using Auth0 library to determine the authentication status.
  • setSession
    : This method stores user's login information like
    access_token
    ,
    id_token
    , and
    expires_at
    into local storage to facilitate the management of these data.
  • logout
    : This method removes all information about logged in user from local storage and sets
    this.loggedin
    value to
    false
    .
  • isAuthenticated
    : This method checks if the user is authenticated or not by checking the
    token
    expiration date from local storage.

Creating Pipes in Ionic 4

To see pipes in action, you are going to create a very simple pipe to capitalize the first character of words. As such, the first thing you will need to do is to create the pipe:

# from the project root
ionic g pipe pipes/capitalize

The above command will generate a file named

capitalize.pipe.ts
inside the
./src/app/pipes/
directory. Open this file and replace its content with this:

import {Pipe, PipeTransform} from '@angular/core';

@Pipe({
  name: 'capitalize'
})
export class CapitalizePipe implements PipeTransform {
  transform(value: any, args?: any): any {
    return this.capitalize(value);
  }

  capitalize(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }
}

The

capitalize
method takes a string as an input and returns another string by capitalizing the first character of that string. When you use
capitalize
pipe inside Angular Template, it will call the transform method, which will further the call to this
capitalize
method from this pipe.

As you will need to use pipes in multiple sub-modules inside your application, it's a good idea to create an extra

NgModule
for all the pipes and then import those modules in your other modules. To do so, create a file named
pipes.module.ts
inside
./src/app/pipes/
directory and add the following code to it:

import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {CapitalizePipe} from './capitalize.pipe';

@NgModule({
  imports: [
    CommonModule,
  ],
  declarations: [CapitalizePipe],
  exports: [CapitalizePipe]
})
export class AppPipesModule { }

Creating Pages in Ionic 4

By Default, the blank ionic project has only one page called

HomePage
. To avoid creating a new one and removing this one, you will use that page to show the list of people.

So, replace the content of the

./src/app/home/home.page.ts
with the following:

import { Component, OnInit } from '@angular/core';
import { DataService } from '../services/data/data.service';
import { NavController } from '@ionic/angular';
import { AuthService } from '../services/auth/auth.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
  people: Array<any> = [];
  constructor(private dataService: DataService, private navCtrl: NavController, private authService: AuthService) {
  }

  ngOnInit() {
    this.dataService.getPeopleList()
    .subscribe((people: any) => {
      this.people = people;
    });
  }

  openPerson(index) {
    this.navCtrl.navigateForward(`/person/${index}`);
  }
}

Then, replace the content of the

./src/app/home/home.page.html
file with the following:

<ion-header>
  <ion-toolbar color="primary">
    <ion-title>
      People
    </ion-title>
    <ion-buttons slot="end">
      <ion-button shape="round" fill="outline" color="light" (click)="authService.login()" *ngIf="!authService.isLoggedIn">Login</ion-button>
      <ion-button shape="round" fill="outline" color="light" (click)="authService.logout()" *ngIf="authService.isLoggedIn">Logout</ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>
<ion-content>
  <ion-list>
      <ion-item *ngFor="let person of people; let i = index" (click)="openPerson(i)">
          <ion-avatar slot="start">
            <img [src]="person.picture.thumbnail" />
          </ion-avatar>
          <ion-label>
            <h2>{{ person.name?.title | capitalize }} {{ person.name?.first | capitalize }} {{person.name?.last | capitalize }}</h2>
          </ion-label>
        </ion-item>  
    </ion-list>  
</ion-content>

Since each page in Ionic is lazily loaded by default, each page comes with its own

NgModule
. As such, you need to import the
AppPipesModule
you just created in your
./src/app/home/home.module.ts
file, as shown below:

// ... other imports ...
import {AppPipesModule} from '../pipes/pipes.module';

@NgModule({
  imports: [
    // ... other imports ...
    AppPipesModule,
  ],
  // ... the rest of the config ...
})
export class HomePageModule {}

When users open your application, the app will load the home page. This homepage shows a list of people with their names and avatar. Users can click on anyone from the list and, clicking on any item, will trigger the

openPerson
method from the
HomePage
component. This will make your app load the
/person
route with that person's
id
as a query parameter.

As such, you will also need to create a new page to show the details of a particular person. You can call this new page as

PersonPage
and create it as follows:

# from the project root
ionic g page person

This will generate multiple files related to the

PersonPage
inside the
./src/app/person/
directory. Now, open the
./src/app/person/person.page.ts
and replace its contents with this:

import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, ParamMap, Router} from '@angular/router';
import {DataService} from '../services/data/data.service';
import {AuthService} from '../services/auth/auth.service';
import {switchMap} from 'rxjs/operators';

@Component({
  selector: 'app-person',
  templateUrl: './person.page.html',
  styleUrls: ['./person.page.scss'],
})
export class PersonPage implements OnInit {
  person: any;

  constructor(private dataService: DataService, private authService: AuthService,
              private route: ActivatedRoute,
              private router: Router) {
  }

  ngOnInit() {
    this.route.paramMap
      .pipe(
        switchMap((params: ParamMap) => this.dataService.getPerson(params.get('id')))
      ).subscribe(person => {
      this.person = person;
    });
  }
}

Also, replace the contents of the

./src/app/person/person.page.html
file with the following:

<ion-header>
  <ion-toolbar color="secondary">
    <ion-buttons slot="start">
      <ion-back-button></ion-back-button>
    </ion-buttons>
    <ion-title>Person</ion-title>
    <ion-buttons slot="end">
      <ion-button routerLink="/home" routerDirection="root">Switch User</ion-button>
      <ion-button shape="round" fill="outline" color="light"  (click)="authService.login()" *ngIf="!authService.isLoggedIn">Login</ion-button>
      <ion-button shape="round" fill="outline" color="light"  (click)="authService.logout()" *ngIf="authService.isLoggedIn">Logout</ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>
<ion-content>
<ion-card *ngIf="person">
  <ion-img [src]="person.picture?.large"></ion-img>
  <ion-card-content>
    <ion-card-title>{{ person.name?.title | capitalize }} {{ person.name?.first | capitalize }} {{ person.name?.last | capitalize }}</ion-card-title>
    <div padding *ngIf="!authService.isLoggedIn">
      <ion-button color="secondary" shape="round" fill="outline" (click)="authService.login()">Login to See More Detail</ion-button>
    </div>
    <div padding [hidden]="!authService.isLoggedIn">
      <ion-item icon-left>
          <span ngClass="flag-icon flag-icon-{{person.nat | lowercase}}"></span>
          <ion-icon slot="start" [name]="person.gender"></ion-icon>
        </ion-item>
      <ion-item icon-left>
          <ion-icon slot="start" name="call"></ion-icon>
          {{ person.phone }}
      </ion-item>
      <ion-item text-wrap>
          <ion-icon slot="start" name="mail"></ion-icon>
          {{ person.email }}
      </ion-item>
      <ion-button color="secondary" shape="round" fill="outline" (click)="authService.logout()">Logout</ion-button>
    </div>
  </ion-card-content>
</ion-card>
</ion-content>

Although the code of this new page is lengthy, you can see that it is not making anything too complex. When users click on someone from the list of people, the will open the

PersonPage
. Then, on this page, users will be able to see information about that person. Some information is hidden and can be seen after logging in (
[hidden]="!authService.isLoggedIn"
).

The last thing you will need to do in relation to your

PersonPage
is to import the
AppPipesModule
you created before in the
./src/app/person/person.module.ts
file, as shown below:

// ... other imports ...
import {AppPipesModule} from '../pipes/pipes.module';

@NgModule({
  imports: [
    // ... other imports ...
    AppPipesModule,
  ],
  // ... the rest of the config ...
})
export class PersonPageModule {}

Importing the Flag Icon Library

Since you want to show some nice country flags alongside with each person's detail, you will have to import this library inside your

global.scss
file. To do so, open this file and add the following line into it:

@import "~flag-icon-css/css/flag-icon.min.css";

Handling Authentication

After authentication requests are processed, Auth0 redirects users back to your application. Alongside with the user, it sends back authentication data via URL hashes. You need to parse that data and save it somewhere. As you probably remember, there is a method called

handleAuthentication
in the
AuthService
to do this. Now, you just have to call this method inside the constructor of
app.component.ts
, as shown below:

// ... other import statements ...
import { AuthService } from './services/auth/auth.service';

// ... @Component definition ...
export class AppComponent {
  constructor(
    private platform: Platform,
    private splashScreen: SplashScreen,
    private statusBar: StatusBar,
    private authService: AuthService
  ) {
    this.initializeApp();
    this.authService.handleAuthentication();
  }

  // ... initializeApp ...
}

Now, whenever you start a new project with Ionic CLI, it generates a module called

app-routing.module.ts
for handling routing in your app. This file contains all the routing configuration. When you generate a page, CLI also adds that page to the routing configuration in this file. As such, you should have following in the
app-routing.module.ts
file:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: './home/home.module#HomePageModule' },
  { path: 'person', loadChildren: './person/person.module#PersonPageModule' },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

To make your

PersonPage
support query parameters, modify the
path: 'person'
route in the above file, as follows:

{ path: 'person/:id', loadChildren: './person/person.module#PersonPageModule' },

Then, to wrap things up, you will have to update the

app.module.ts
file (which is located inside the
/src/app/
directory) to tie everything together. In this file, you will need to add all the services, pipes, and pages that you created into it so that Angular can recognize them:

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {RouteReuseStrategy} from '@angular/router';
import {HttpClientModule} from '@angular/common/http';
import {IonicModule, IonicRouteStrategy} from '@ionic/angular';
import {SplashScreen} from '@ionic-native/splash-screen/ngx';
import {StatusBar} from '@ionic-native/status-bar/ngx';

import {AppComponent} from './app.component';
import {AppRoutingModule} from './app-routing.module';
import {AuthService} from './services/auth/auth.service';
import {DataService} from './services/data/data.service';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, HttpClientModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    StatusBar,
    SplashScreen,
    AuthService,
    DataService,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Now you can run the application as follows:

ionic serve

Note: If you get an error like, CapitalizePipe is declared in two modules, it's because, when you create a pipe using Ionic CLI, it also adds that pipe inside the

app.module.ts
file. In this case, you have to remove
CapitalizePipe
from the
app.module.ts
file.

Now, if you open the app in your browser (which actually Ionic does by default for you), you will see the following screen:

Developing apps with Ionic 4

Developing apps with Ionic 4

I just built my first Ionic 4 app.

Tweet This

Conclusion

In this post, you learned about what's new in Ionic 4, changes from Ionic 3, and how to migrate to the new version. After that, you learned about using Stencil and Capacitor along with Ionic to create mobile applications and, finally, you created and secured a simple Ionic 4 app. To learn more about Ionic 4, check out the official Ionic 4 documentation.