Ionic 4 and Angular 7 Tutorial: HTTP Interceptor Example

Ionic 4 and Angular 7 Tutorial: HTTP Interceptor Example

The comprehensive step by step tutorial on using HTTP Interceptor with Ionic 4 and Angular 7 including a complete example of authentication or login.

The comprehensive step by step tutorial on using HTTP Interceptor with Ionic 4 and Angular 7 including a complete example of authentication or login. We will stick Authentication Token to Angular 7 interceptor. So, you don’t have to repeat calling token when call or consume RESTful API. For the RESTful API, we will use our existing Node, Express, Passport and MongoDB that you can get from our GitHub.

Table of Contents:

The following tools, frameworks, and modules are required for this tutorial:

Before going to the main steps, we assume that you have to install Node.js. Next, upgrade or install new Ionic 4 CLI by open the terminal or Node command line then type this command.

sudo npm install -g ionic

You will get the latest Ionic CLI in your terminal or command line. Check the version by type this command.

ionic --version
4.3.1

1. Create a new Ionic 4 and Angular 7 App

To create a new Ionic 4 and Angular 7 application, type this command in your terminal.

ionic start ionic4-angular7-interceptor blank --type=angular

If you see this question, just type N for because we will installing or adding Cordova later.

Integrate your new app with Cordova to target native iOS and Android? (y/N) N

After installing NPM modules and dependencies, you will see this question, just type N because we are not using it yet.

Install the free Ionic Pro SDK and connect your app? (Y/n) N

Next, go to the newly created app folder.

cd ./ionic4-angular7-interceptor

As usual, run the Ionic 4 and Angular 7 app for the first time, but before run as lab mode, type this command to install @ionic/lab.

npm install --save-dev @ionic/lab
ionic serve -l

Now, open the browser and you will the Ionic 4 and Angular 7 app with the iOS, Android, or Windows view. If you see a normal Ionic 4 blank application, that’s mean you ready to go to the next steps.

2. Create a custom Angular 7 HttpInterceptor

Before creating a custom Angular 7 HttpInterceptor, create a folder under app folder.

mkdir src/app/interceptors

Next, create a file for the custom Angular 7 HttpInterceptor.

touch src/app/interceptors/token.interceptor.ts

Open and edit that file the add this imports.

import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpResponse,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import {
  Router
} from '@angular/router';
import { ToastController } from '@ionic/angular';

Create a class that implementing HttpInterceptor method.

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

}

Inject the required module to the constructor inside the class.

constructor(private router: Router,
  public toastController: ToastController) {}

Implement a custom Interceptor function.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

&nbsp; const token = localStorage.getItem('token');

&nbsp; if (token) {
&nbsp; &nbsp; request = request.clone({
&nbsp; &nbsp; &nbsp; setHeaders: {
&nbsp; &nbsp; &nbsp; &nbsp; 'Authorization': token
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; });
&nbsp; }

&nbsp; if (!request.headers.has('Content-Type')) {
&nbsp; &nbsp; request = request.clone({
&nbsp; &nbsp; &nbsp; setHeaders: {
&nbsp; &nbsp; &nbsp; &nbsp; 'content-type': 'application/json'
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; });
&nbsp; }

&nbsp; request = request.clone({
&nbsp; &nbsp; headers: request.headers.set('Accept', 'application/json')
&nbsp; });

&nbsp; return next.handle(request).pipe(
&nbsp; &nbsp; map((event: HttpEvent<any>) => {
&nbsp; &nbsp; &nbsp; if (event instanceof HttpResponse) {
&nbsp; &nbsp; &nbsp; &nbsp; console.log('event--->>>', event);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; return event;
&nbsp; &nbsp; }),
&nbsp; &nbsp; catchError((error: HttpErrorResponse) => {
&nbsp; &nbsp; &nbsp; if (error.status === 401) {
&nbsp; &nbsp; &nbsp; &nbsp; if (error.error.success === false) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.presentToast('Login failed');
&nbsp; &nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.router.navigate(['login']);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; return throwError(error);
&nbsp; &nbsp; }));
}

Add function for call a toast controller.

async presentToast(msg) {
&nbsp; const toast = await this.toastController.create({
&nbsp; &nbsp; message: msg,
&nbsp; &nbsp; duration: 2000,
&nbsp; &nbsp; position: 'top'
&nbsp; });
&nbsp; toast.present();
}

Next, we have to register this custom HttpInterceptor and HttpClientModule. Open and edit src/app/app.module.ts then add this imports.

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { TokenInterceptor } from './inteceptors/token.interceptor';

Add those modules to the provider array of the @NgModule.

providers: [
&nbsp; StatusBar,
&nbsp; SplashScreen,
&nbsp; { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
&nbsp; {
&nbsp; &nbsp; provide: HTTP_INTERCEPTORS,
&nbsp; &nbsp; useClass: TokenInterceptor,
&nbsp; &nbsp; multi: true
&nbsp; }
],

Now, the HTTP interceptor is ready to intercept any request to the API.

3. Create Ionic 4 Angular 7 Authentication and Book Services

First, create a folder for those services under src/app/.

mkdir src/app/services

Create services or providers for authentication and book.

ionic g service services/auth
ionic g service services/book

Next, open and edit src/app/services/auth.service.ts then replace all codes with this.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

@Injectable({
&nbsp; providedIn: 'root'
})
export class AuthService {

&nbsp; apiUrl = 'http://localhost:3000/api/';

&nbsp; constructor(private http: HttpClient) { }

&nbsp; login (data): Observable<any> {
&nbsp; &nbsp; return this.http.post<any>(this.apiUrl + 'signin', data)
&nbsp; &nbsp; &nbsp; .pipe(
&nbsp; &nbsp; &nbsp; &nbsp; tap(_ => this.log('login')),
&nbsp; &nbsp; &nbsp; &nbsp; catchError(this.handleError('login', []))
&nbsp; &nbsp; &nbsp; );
&nbsp; }

&nbsp; logout (): Observable<any> {
&nbsp; &nbsp; return this.http.get<any>(this.apiUrl + 'signout')
&nbsp; &nbsp; &nbsp; .pipe(
&nbsp; &nbsp; &nbsp; &nbsp; tap(_ => this.log('logout')),
&nbsp; &nbsp; &nbsp; &nbsp; catchError(this.handleError('logout', []))
&nbsp; &nbsp; &nbsp; );
&nbsp; }

&nbsp; register (data): Observable<any> {
&nbsp; &nbsp; return this.http.post<any>(this.apiUrl + 'signup', data)
&nbsp; &nbsp; &nbsp; .pipe(
&nbsp; &nbsp; &nbsp; &nbsp; tap(_ => this.log('login')),
&nbsp; &nbsp; &nbsp; &nbsp; catchError(this.handleError('login', []))
&nbsp; &nbsp; &nbsp; );
&nbsp; }

&nbsp; private handleError<T> (operation = 'operation', result?: T) {
&nbsp; &nbsp; return (error: any): Observable<T> => {

&nbsp; &nbsp; &nbsp; // TODO: send the error to remote logging infrastructure
&nbsp; &nbsp; &nbsp; console.error(error); // log to console instead

&nbsp; &nbsp; &nbsp; // TODO: better job of transforming error for user consumption
&nbsp; &nbsp; &nbsp; this.log(`${operation} failed: ${error.message}`);

&nbsp; &nbsp; &nbsp; // Let the app keep running by returning an empty result.
&nbsp; &nbsp; &nbsp; return of(result as T);
&nbsp; &nbsp; };
&nbsp; }

&nbsp; /** Log a HeroService message with the MessageService */
&nbsp; private log(message: string) {
&nbsp; &nbsp; console.log(message);
&nbsp; }
}

Next, open and edit src/app/services/book.service then replace all codes with this.

import { Injectable } from '@angular/core';
import { Book } from '../book/book';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

@Injectable({
&nbsp; providedIn: 'root'
})
export class BookService {

&nbsp; apiUrl = 'http://localhost:3000/api/';

&nbsp; constructor(private http: HttpClient) { }

&nbsp; getBooks (): Observable<Book[]> {
&nbsp; &nbsp; return this.http.get<Book[]>(this.apiUrl + 'book')
&nbsp; &nbsp; &nbsp; .pipe(
&nbsp; &nbsp; &nbsp; &nbsp; tap(_ => this.log('fetched books')),
&nbsp; &nbsp; &nbsp; &nbsp; catchError(this.handleError('getBooks', []))
&nbsp; &nbsp; &nbsp; );
&nbsp; }

&nbsp; private handleError<T> (operation = 'operation', result?: T) {
&nbsp; &nbsp; return (error: any): Observable<T> => {

&nbsp; &nbsp; &nbsp; // TODO: send the error to remote logging infrastructure
&nbsp; &nbsp; &nbsp; console.error(error); // log to console instead

&nbsp; &nbsp; &nbsp; // TODO: better job of transforming error for user consumption
&nbsp; &nbsp; &nbsp; this.log(`${operation} failed: ${error.message}`);

&nbsp; &nbsp; &nbsp; // Let the app keep running by returning an empty result.
&nbsp; &nbsp; &nbsp; return of(result as T);
&nbsp; &nbsp; };
&nbsp; }

&nbsp; /** Log a HeroService message with the MessageService */
&nbsp; private log(message: string) {
&nbsp; &nbsp; console.log(message);
&nbsp; }
}

4. Create an Ionic 4 and Angular 7 Book Page

Type this command to generate an Ionic 4 and Angular 7 page for the book.

ionic g page book

Create a Typescript file for handle Book object or as a model for Book object.

touch src/app/book/book.ts

Open end edit that file then replaces all codes with this.

export class Book {
&nbsp; _id: number;
&nbsp; isbn: string;
&nbsp; title: string;
&nbsp; author: number;
&nbsp; publisher: Date;
&nbsp; __v: number;
}

Next, open and edit src/app/book/book.page.ts then add this imports.

import { Book } from './book';
import { BookService } from '../services/book.service';
import { AuthService } from '../services/auth.service';
import { Router } from '@angular/router';

Inject all required modules to the constructor.

constructor(private bookService: BookService,
&nbsp; private authService: AuthService,
&nbsp; private router: Router) { }

Declare this variable before the constructor.

books: Book[];

Create a function for consuming or get book list from the book service.

getBooks(): void {
&nbsp; this.bookService.getBooks()
&nbsp; &nbsp; .subscribe(books => {
&nbsp; &nbsp; &nbsp; console.log(books);
&nbsp; &nbsp; &nbsp; this.books = books;
&nbsp; &nbsp; });
}

Call this function from ngOnInit.

ngOnInit() {
&nbsp; this.getBooks();
}

Add a function for log out the current session.

logout() {
&nbsp; this.authService.logout()
&nbsp; &nbsp; .subscribe(res => {
&nbsp; &nbsp; &nbsp; console.log(res);
&nbsp; &nbsp; &nbsp; localStorage.removeItem('token');
&nbsp; &nbsp; &nbsp; this.router.navigate(['login']);
&nbsp; &nbsp; });
}

Next, open and edit src/app/book/book.page.html then replace all HTML tags with this.

<ion-header>
&nbsp; <ion-toolbar>
&nbsp; &nbsp; <ion-title>List of Books</ion-title>
&nbsp; &nbsp; <ion-buttons slot="end">
&nbsp; &nbsp; &nbsp; <ion-button color="secondary" (click)="logout()">
&nbsp; &nbsp; &nbsp; &nbsp; <ion-icon slot="icon-only" name="exit"></ion-icon>
&nbsp; &nbsp; &nbsp; </ion-button>
&nbsp; &nbsp; </ion-buttons>
&nbsp; </ion-toolbar>
</ion-header>

<ion-content padding>
&nbsp; <ion-list>
&nbsp; &nbsp; <ion-item *ngFor="let b of books">
&nbsp; &nbsp; &nbsp; <ion-label>{{b.title}}</ion-label>
&nbsp; &nbsp; </ion-item>
&nbsp; </ion-list>
</ion-content>

The book page just shows the list of the book and log out button on the title bar.

5. Create the Ionic 4 and Angular 7 Pages for Login and Register

Before creating that pages, create this folder under src/app.

mkdir src/app/auth

Now, generate the Ionic 4 and Angular 7 pages.

ionic g page auth/login
ionic g page auth/register

Next, open and edit src/app/auth/login/login.page.ts then replace all codes with this.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';
import { ToastController } from '@ionic/angular';

@Component({
&nbsp; selector: 'app-login',
&nbsp; templateUrl: './login.page.html',
&nbsp; styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {

&nbsp; loginForm: FormGroup;

&nbsp; constructor(private formBuilder: FormBuilder,
&nbsp; &nbsp; private router: Router,
&nbsp; &nbsp; private authService: AuthService,
&nbsp; &nbsp; public toastController: ToastController) { }

&nbsp; ngOnInit() {
&nbsp; &nbsp; this.loginForm = this.formBuilder.group({
&nbsp; &nbsp; &nbsp; 'username' : [null, Validators.required],
&nbsp; &nbsp; &nbsp; 'password' : [null, Validators.required]
&nbsp; &nbsp; });
&nbsp; }

&nbsp; onFormSubmit(form: NgForm) {
&nbsp; &nbsp; this.authService.login(form)
&nbsp; &nbsp; &nbsp; .subscribe(res => {
&nbsp; &nbsp; &nbsp; &nbsp; if (res.token) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; localStorage.setItem('token', res.token);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.router.navigate(['book']);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }, (err) => {
&nbsp; &nbsp; &nbsp; &nbsp; console.log(err);
&nbsp; &nbsp; &nbsp; });
&nbsp; }

&nbsp; register() {
&nbsp; &nbsp; this.router.navigate(['register']);
&nbsp; }

&nbsp; async presentToast(msg) {
&nbsp; &nbsp; const toast = await this.toastController.create({
&nbsp; &nbsp; &nbsp; message: msg,
&nbsp; &nbsp; &nbsp; duration: 2000,
&nbsp; &nbsp; &nbsp; position: 'top'
&nbsp; &nbsp; });
&nbsp; &nbsp; toast.present();
&nbsp; }

}

Next, open and edit src/app/auth/login/login.page.html then replace all HTML tags with this.

<ion-content padding>
&nbsp; <form [formGroup]="loginForm" (ngSubmit)="onFormSubmit(loginForm.value)">
&nbsp; &nbsp; <ion-card>
&nbsp; &nbsp; &nbsp; <ion-card-header>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-card-title>Please, Sign In</ion-card-title>
&nbsp; &nbsp; &nbsp; </ion-card-header>
&nbsp; &nbsp; &nbsp; <ion-card-content>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-label position="floating">Username</ion-label>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-input type="text" formControlName="username"></ion-input>
&nbsp; &nbsp; &nbsp; &nbsp; </ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-label position="floating">Password</ion-label>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-input type="password" formControlName="password"></ion-input>
&nbsp; &nbsp; &nbsp; &nbsp; </ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-item lines="none" lines="full" padding-top>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-button expand="full" size="default" shape="round" color="success" type="submit" [disabled]="!loginForm.valid">Login</ion-button>
&nbsp; &nbsp; &nbsp; &nbsp; </ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-item lines="none">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-button type="button" expand="full" size="default" shape="round" color="medium" (click)="register()">Register</ion-button>
&nbsp; &nbsp; &nbsp; &nbsp; </ion-item>
&nbsp; &nbsp; &nbsp; </ion-card-content>
&nbsp; &nbsp; </ion-card>
&nbsp; </form>
</ion-content>

Next, open and edit src/app/auth/register/register.page.ts then replace all codes with this.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';
import { ToastController, AlertController } from '@ionic/angular';

@Component({
&nbsp; selector: 'app-register',
&nbsp; templateUrl: './register.page.html',
&nbsp; styleUrls: ['./register.page.scss'],
})
export class RegisterPage implements OnInit {

&nbsp; registerForm: FormGroup;

&nbsp; constructor(private formBuilder: FormBuilder,
&nbsp; &nbsp; private router: Router,
&nbsp; &nbsp; private authService: AuthService,
&nbsp; &nbsp; public toastController: ToastController,
&nbsp; &nbsp; public alertController: AlertController) { }

&nbsp; ngOnInit() {
&nbsp; &nbsp; this.registerForm = this.formBuilder.group({
&nbsp; &nbsp; &nbsp; 'username' : [null, Validators.required],
&nbsp; &nbsp; &nbsp; 'password' : [null, Validators.required]
&nbsp; &nbsp; });
&nbsp; }

&nbsp; onFormSubmit(form: NgForm) {
&nbsp; &nbsp; this.authService.register(form)
&nbsp; &nbsp; &nbsp; .subscribe(_ => {
&nbsp; &nbsp; &nbsp; &nbsp; this.presentAlert('Register Successfully', 'Please login with your new username and password');
&nbsp; &nbsp; &nbsp; }, (err) => {
&nbsp; &nbsp; &nbsp; &nbsp; console.log(err);
&nbsp; &nbsp; &nbsp; });
&nbsp; }

&nbsp; async presentToast(msg) {
&nbsp; &nbsp; const toast = await this.toastController.create({
&nbsp; &nbsp; &nbsp; message: msg,
&nbsp; &nbsp; &nbsp; duration: 2000,
&nbsp; &nbsp; &nbsp; position: 'top'
&nbsp; &nbsp; });
&nbsp; &nbsp; toast.present();
&nbsp; }

&nbsp; async presentAlert(header, message) {
&nbsp; &nbsp; const alert = await this.alertController.create({
&nbsp; &nbsp; &nbsp; header: header,
&nbsp; &nbsp; &nbsp; message: message,
&nbsp; &nbsp; &nbsp; buttons: [{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text: 'OK',
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handler: () => {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.router.navigate(['login']);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }]
&nbsp; &nbsp; });

&nbsp; &nbsp; await alert.present();
&nbsp; }

}

Open and edit src/app/auth/login/login.page.html then replace all HTML tags with this.

<ion-header>
&nbsp; <ion-toolbar>
&nbsp; &nbsp; <ion-buttons slot="start">
&nbsp; &nbsp; &nbsp; <ion-back-button></ion-back-button>
&nbsp; &nbsp; </ion-buttons>
&nbsp; &nbsp; <ion-title>Register</ion-title>
&nbsp; </ion-toolbar>
</ion-header>

<ion-content padding>
&nbsp; <form [formGroup]="registerForm" (ngSubmit)="onFormSubmit(registerForm.value)">
&nbsp; &nbsp; <ion-card>
&nbsp; &nbsp; &nbsp; <ion-card-header>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-card-title>Register here</ion-card-title>
&nbsp; &nbsp; &nbsp; </ion-card-header>
&nbsp; &nbsp; &nbsp; <ion-card-content>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-label position="floating">Username</ion-label>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-input type="text" formControlName="username"></ion-input>
&nbsp; &nbsp; &nbsp; &nbsp; </ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-label position="floating">Password</ion-label>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-input type="password" formControlName="password"></ion-input>
&nbsp; &nbsp; &nbsp; &nbsp; </ion-item>
&nbsp; &nbsp; &nbsp; &nbsp; <ion-item lines="none" padding-top>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ion-button expand="full" size="default" shape="round" color="success" type="submit" [disabled]="!registerForm.valid">Register</ion-button>
&nbsp; &nbsp; &nbsp; &nbsp; </ion-item>
&nbsp; &nbsp; &nbsp; </ion-card-content>
&nbsp; &nbsp; </ion-card>
&nbsp; </form>
</ion-content>

6. Run and Test the Ionic 4 and Angular 7 Authentication App

Before the run the Ionic 4 and Angular 7 app, we should run the RESTful API server first. After you clone our Express.js API, run this command in the terminal.

npm i

Open another Terminal tabs if your MongoDB server not running then type this command to run it.

mongod

Back to Express API, type this command to run it.

nodemon

or

npm start

Next, we have to run the Ionic 4 and Angular 7 app by typing this command.

ionic serve -l

You should see these pages if everything working properly.

That it’s, the Ionic 4 and Angular 7 HttpIntercepter and HttpClient implementation to the Authentication app. You can find the full working source code on our GitHub.

We know that building beautifully designed Ionic apps from scratch can be frustrating and very time-consuming. Check Ion2FullApp ELITE - The Complete Ionic 3 Starter App and save development and design time.

Learn More

Angular 7 (formerly Angular 2) - The Complete Guide

Learn and Understand AngularJS

Angular Crash Course for Busy Developers

The Complete Angular Course: Beginner to Advanced

Angular (Angular 2+) & NodeJS - The MEAN Stack Guide

Become a JavaScript developer - Learn (React, Node,Angular)

Angular (Full App) with Angular Material, Angularfire & NgRx

The Web Developer Bootcamp

How to Build Mobile Apps with Angular, Ionic 4, and Spring Boot

How to Build Mobile Apps with Angular, Ionic 4, and Spring Boot

Run Your Ionic App on Android. Make sure you're using Java 8. Run ionic cordova prepare android. Open platforms/android in Android Studio, upgrade Gradle if prompted. Set launchMode to singleTask in AndroidManifest.xml. Start your app using Android Studio...

In this brief tutorial, I’ll show you to use Ionic for JHipster v4 with Spring Boot and JHipster 6.

To complete this tutorial, you’ll need to have Java 8+, Node.js 10+, and Docker installed. You’ll also need to create an Okta developer account.

Create a Spring Boot + Angular App with JHipster

You can install JHipster via Homebrew (brew install jhipster) or with npm.

npm i -g [email protected]

Once you have JHipster installed, you have two choices. There’s the quick way to generate an app (which I recommend), and there’s the tedious way of picking all your options. I don’t care which one you use, but you must select OAuth 2.0 / OIDCauthentication to complete this tutorial successfully.

Here’s the easy way:

mkdir app && cd app

echo "application { config { baseName oauth2, authenticationType oauth2, \
  buildTool gradle, testFrameworks [protractor] }}" >> app.jh

jhipster import-jdl app.jh

The hard way is you run jhipster and answer a number of questions. There are so many choices when you run this option that you might question your sanity. At last count, I remember reading that JHipster allows 26K+ combinations!

The project generation process will take a couple of minutes to complete if you’re on fast internet and have a bad-ass laptop. When it’s finished, you should see output like the following.

OIDC with Keycloak and Spring Security

JHipster has several authentication options: JWT, OAuth 2.0 / OIDC, and UAA. With JWT (the default), you store the access token on the client (in local storage). This works but isn’t the most secure. UAA involves using your own OAuth 2.0 authorization server (powered by Spring Security), and OAuth 2.0 / OIDC allows you to use Keycloak or Okta.

Spring Security makes Keycloak and Okta integration so incredibly easy it’s silly. Keycloak and Okta are called "identity providers" and if you have a similar solution that is OIDC-compliant, I’m confident it’ll work with Spring Security and JHipster.

Having Keycloak set by default is nice because you can use it without having an internet connection.

To log into the JHipster app you just created, you’ll need to have Keycloak up and running. When you create a JHipster project with OIDC for authentication, it creates a Docker container definition that has the default users and roles. Start Keycloak using the following command.

docker-compose -f src/main/docker/keycloak.yml up -d

Start your application with ./gradlew (or ./mvnw if you chose Maven) and you should be able to log in using "admin/admin" for your credentials.

Open another terminal and prove all the end-to-end tests pass:

npm run e2e

If your environment is setup correctly, you’ll see output like the following:

> [email protected] e2e /Users/mraible/app
> protractor src/test/javascript/protractor.conf.js

[16:02:18] W/configParser - pattern ./e2e/entities/**/*.spec.ts did not match any files.
[16:02:18] I/launcher - Running 1 instances of WebDriver
[16:02:18] I/direct - Using ChromeDriver directly...


  account
    ✓ should fail to login with bad password
    ✓ should login successfully with admin account (1754ms)

  administration
    ✓ should load metrics
    ✓ should load health
    ✓ should load configuration
    ✓ should load audits
    ✓ should load logs


  7 passing (15s)

[16:02:36] I/launcher - 0 instance(s) of WebDriver still running
[16:02:36] I/launcher - chrome #01 passed
Execution time: 19 s.

OIDC with Okta and Spring Security

To switch to Okta, you’ll first need to create an OIDC app. If you don’t have an Okta Developer account, now is the time!

Log in to your Okta Developer account.

  • In the top menu, click on Applications
  • Click on Add Application
  • Select Web and click Next
  • Enter JHipster FTW! for the Name (this value doesn’t matter, so feel free to change it)
  • Change the Login redirect URI to be <a href="http://localhost:8080/login/oauth2/code/oidc" target="_blank">http://localhost:8080/login/oauth2/code/oidc</a>
  • Click Done, then Edit and add <a href="http://localhost:8080" target="_blank">http://localhost:8080</a> as a Logout redirect URI
  • Click Save

These are the steps you’ll need to complete for JHipster. Start your JHipster app using a command like the following:

SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI=https://{yourOktaDomain}/oauth2/default \
  SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID=$clientId \
  SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET=$clientSecret ./gradlew

Create a Native App for Ionic

You’ll also need to create a Native app for Ionic. The reason for this is because Ionic for JHipster is configured to use PKCE(Proof Key for Code Exchange). The current Spring Security OIDC support in JHipster still requires a client secret. PKCE does not.

Go back to the Okta developer console and follow the steps below:

  • In the top menu, click on Applications
  • Click on Add Application
  • Select Native and click Next
  • Enter Ionic FTW! for the Name
  • Add Login redirect URIs: <a href="http://localhost:8100/implicit/callback" target="_blank">http://localhost:8100/implicit/callback</a> and dev.localhost.ionic:/callback
  • Click Done, then Edit and add Logout redirect URIs: <a href="http://localhost:8100/implicit/logout" target="_blank">http://localhost:8100/implicit/logout</a> and dev.localhost.ionic:/logout
  • Click Save

You’ll need the client ID from your Native app, so keep your browser tab open or copy/paste it somewhere.

Create Groups and Add Them as Claims to the ID Token

In order to login to your JHipster app, you’ll need to adjust your Okta authorization server to include a groups claim.

On Okta, navigate to Users > Groups. Create ROLE_ADMIN and ROLE_USER groups and add your account to them.

Navigate to API > Authorization Servers, click the Authorization Servers tab and edit the default one. Click the Claims tab and Add Claim. Name it "groups" or "roles" and include it in the ID Token. Set the value type to "Groups" and set the filter to be a Regex of .*. Click Create.

Navigate to <a href="http://localhost:8080" target="_blank">http://localhost:8080</a>, click sign in and you’ll be redirected to Okta to log in.

Enter the credentials you used to signup for your account, and you should be redirected back to your JHipster app.

Generate Entities for a Photo Gallery

Let’s enhance this example a bit and create a photo gallery that you can upload pictures to. Kinda like Flickr, but waaayyyy more primitive.

JHipster has a JDL (JHipster Domain Language) feature that allows you to model the data in your app, and generate entities from it. You can use its JDL Studio feature to do this online and save it locally once you’ve finished.

I created a data model for this app that has an Album, Photo, and Tag entities and set up relationships between them. Below is a screenshot of what it looks like in JDL Studio.

Copy the JDL below and save it in a photos.jdl file in the root directory of your project.

entity Album {
  title String required,
  description TextBlob,
  created Instant
}

entity Photo {
  title String required,
  description TextBlob,
  image ImageBlob required,
  taken Instant
}

entity Tag {
  name String required minlength(2)
}

relationship ManyToOne {
  Album{user(login)} to User,
  Photo{album(title)} to Album
}

relationship ManyToMany {
  Photo{tag(name)} to Tag{photo}
}

paginate Album with pagination
paginate Photo, Tag with infinite-scroll

You can generate entities and CRUD code (Java for Spring Boot; TypeScript and HTML for Angular) using the following command:

jhipster import-jdl photos.jdl

When prompted, type a to update existing files.

This process will create Liquibase changelog files (to create your database tables), entities, repositories, Spring MVC controllers, and all the Angular code that’s necessary to create, read, update, and delete your data objects. It’ll even generate Jest unit tests and Protractor end-to-end tests!

When the process completes, restart your app, and confirm that all your entities exist (and work) under the Entities menu.

You might notice that the entity list screen is pre-loaded with data. This is done by faker.js. To turn it off, edit src/main/resources/config/application-dev.yml, search for liquibase and set its contexts value to dev. I made this change in this example’s code and ran ./gradlew clean to clear the database.

liquibase:
  # Add 'faker' if you want the sample data to be loaded automatically
  contexts: dev

Develop a Mobile App with Ionic and Angular

Getting started with Ionic for JHipster is similar to JHipster. You simply have to install the Ionic CLI, Yeoman, the module itself, and run a command to create the app.

npm i -g [email protected] [email protected] yo
yo jhipster-ionic

If you have your app application at ~/app, you should run this command from your home directory (~). Ionic for JHipster will prompt you for the location of your backend application. Use mobile for your app’s name and app for the JHipster app’s location.

Type a when prompted to overwrite mobile/src/app/app.component.ts.

Open mobile/src/app/auth/auth.service.ts in an editor, search for data.clientId and replace it with the client ID from your Native app on Okta.

// try to get the oauth settings from the server
this.requestor.xhr({method: 'GET', url: AUTH_CONFIG_URI}).then(async (data: any) => {
  this.authConfig = {
    identity_client: '{yourClientId}',
    identity_server: data.issuer,
    redirect_url: redirectUri,
    end_session_redirect_url: logoutRedirectUri,
    scopes,
    usePkce: true
  };
  ...
}

When using Keycloak, this change is not necessary.### Add Claims to Access Token

In order to authentication successfully with your Ionic app, you have to do a bit more configuration in Okta. Since the Ionic client will only send an access token to JHipster, you need to 1) add a groups claim to the access token and 2) add a couple more claims so the user’s name will be available in JHipster.

Navigate to API > Authorization Servers, click the Authorization Servers tab and edit the default one. Click the Claims tab and Add Claim. Name it "groups" and include it in the Access Token. Set the value type to "Groups" and set the filter to be a Regex of .*. Click Create.

Add another claim, name it given_name, include it in the access token, use Expression in the value type, and set the value to user.firstName. Optionally, include it in the profile scope. Perform the same actions to create a family_name claim and use expression user.lastName.

When you are finished, your claims should look as follows.

Run the following commands to start your Ionic app.

cd mobile
ionic serve

You’ll see a screen with a sign-in button. Click on it, and you’ll be redirected to Okta to authenticate.

Now that you having log in working, you can use the entity generator to generate Ionic pages for your data model. Run the following commands (in your ~/mobile directory) to generate screens for your entities.

yo jhipster-ionic:entity album

When prompted to generate this entity from an existing one, type Y. Enter ../app as the path to your existing application. When prompted to regenerate entities and overwrite files, type Y. Enter a when asked about conflicting files.

Go back to your browser where your Ionic app is running (or restart it if you stopped it). Click on Entities on the bottom, then Albums. Click the blue + icon in the bottom corner, and add a new album.

Click the ✔️ in the top right corner to save your album. You’ll see a success message and it listed on the next screen.

Refresh your JHipster app’s album list and you’ll see it there too!

Generate code for the other entities using the following commands and the same answers as above.

yo jhipster-ionic:entity photo
yo jhipster-ionic:entity tag

Run Your Ionic App on iOS

To generate an iOS project for your Ionic application, run the following command:

ionic cordova prepare ios

When prompted to install the ios platform, type Y. When the process completes, open your project in Xcode:

open platforms/ios/MyApp.xcworkspace

You’ll need to configure code signing in the General tab, then you should be able to run your app in Simulator.

Log in to your Ionic app, tap Entities and view the list of photos.

Add a photo in the JHipster app at <a href="http://localhost:8080" target="_blank">http://localhost:8080</a>.

To see this new album in your Ionic app, pull down with your mouse to simulate the pull-to-refresh gesture on a phone. Looky there - it works!

There are some gestures you should know about on this screen. Clicking on the row will take you to a view screen where you can see the photo’s details. You can also swipe left to expose edit and delete buttons.

Run Your Ionic App on Android

Deploying your app on Android is very similar to iOS. In short:

  1. Make sure you’re using Java 8
  2. Run ionic cordova prepare android
  3. Open platforms/android in Android Studio, upgrade Gradle if prompted
  4. Set launchMode to singleTask in AndroidManifest.xml
  5. Start your app using Android Studio
  6. While your app is starting, run adb reverse tcp:8080 tcp:8080 so the emulator can talk to JHipster
Learn More About Ionic 4 and JHipster 6

Ionic is a nice way to leverage your web development skills to build mobile apps. You can do most of your development in the browser, and deploy to your device when you’re ready to test it. You can also just deploy your app as a PWA and not both to deploy it to an app store.

JHipster supports PWAs too, but I think Ionic apps look like native apps, which is a nice effect. There’s a lot more I could cover about JHipster and Ionic, but this should be enough to get you started.

You can find the source code for the application developed in this post on GitHub at @oktadeveloper/okta-ionic4-jhipster-example.

Thank you for reading!

Angular with ionic 4 required

Please provide me angular and ionic 4 tutorials with some examples.

Please provide me angular and ionic 4 tutorials with some examples.


Thank you.

Ionic 4/Angular Modals - Tutorial

Ionic 4/Angular Modals - Tutorial

In this tutorial, we are going to see how to use modals in Ionic 4/Angular apps by creating a simple demo app so let's get started!

First of all, We need to mention that we are using the Ionic CLI 4 so if you didn't yet upgrade to this release make sure to use the equivalent commands for Ionic CLI prior versions.

Generating a New Ionic 4/Angular Project

Before implementing our modal example, let's first generate a brand new Ionic 4 project based on Angular.

Go ahead and open your terminal window then type the following command:

ionic start ionic-modals blank --type=angular

Next, navigate inside your project directory and serve your app using the following command:

cd ionic-modals
ionic serve 

You should be able to visit your app by going to the http://localhost:8100 address.

Importing and using ModalController

Open src/pages/home/home.ts then import ModalController from ionic-angular:

import { ModalController } from 'ionic-angular';

Next we need to inject via component constructor:

@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController,public modalCtrl : ModalController) {

}

}

Opening a Modal Page

The next step is to add the openModal() method to the HomePage component and bind it to a button on the home.html file:

public openModal(){

}

<button ion-button (click)="openModal()">Open Modal</button>

Before adding an implementation for the openModal() method, let's first add a new page to be used by our modal.

Head to your terminal inside your project folder and run the following command:

ionic g page ModalPage

Then in the home.ts file, use the create() method of ModalController to create a modal and then show it:

public openModal(){ var modalPage = this.modalCtrl.create('ModalPage'); modalPage.present(); }

Now if you click on open modal button you should be able to see a modal page popups.

Closing the Modal Page

We have added a method for opening a modal, now let's add a method to close the modal page once it is opened.

Open the src/pages/modal/modal.tsthen add thecloseModal()method to theModalPage` component:

public closeModal(){

}

Then open the src/pages/modal/modal.html file and add a button to close the modal:

<ion-header>

<ion-navbar>
<ion-title>ModalPage</ion-title>
<ion-buttons end>
<button ion-button (click)="closeModal()">Close</button>
</ion-buttons>
</ion-navbar>

</ion-header>

<ion-content padding>

</ion-content>

Now let's implement the closeModal() method.

First we need to import ViewController from the ionic-angular package:

import { ViewController } from 'ionic-angular';

Inject ViewController via component constructor:

export class ModalPage {

constructor(public viewCtrl : ViewController ) {
}

Next, use the dismiss() method to close the modal:

export class ModalPage {

constructor(public navCtrl: NavController, public viewCtrl : ViewController ,public navParams: NavParams) {
}
public closeModal(){
this.viewCtrl.dismiss();
}

}

Passing Data to Modal Page Component

You can also pass some data to a modal page component using the second parameter of the create() method. Passed data can be of any type: string , number or object.

Go ahead, change the openModal() method to pass some data object:

public openModal(){
var data = { message : 'hello world' };
var modalPage = this.modalCtrl.create('ModalPage',data);
modalPage.present();
}

Now let's get the passed parameters using NavParams:

@IonicPage()
@Component({
selector: 'page-modal',
templateUrl: 'modal.html',
})
export class ModalPage {

constructor(public navCtrl: NavController, public viewCtrl : ViewController ,public navParams: NavParams) {
}
public closeModal(){
this.viewCtrl.dismiss();
}
ionViewDidLoad() {
console.log('ionViewDidLoad ModalPage');
console.log(this.navParams.get('message'));
}

}

Conclusion

This is the end of this tutorial. We have seen how to use modals in Ionic 4/Angular.

Originally published  at  techiediaries.com on 01 Aug 2019

==========================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Ionic 4, Angular 7 and Cordova Crop and Upload Image

Ionic 4 - Build iOS, Android & Web Apps with Ionic & Angular

Building CRUD Mobile App using Ionic 4, Angular 8

How to Build Mobile Apps with Angular, Ionic 4, and Spring Boot

Ionic 4 JWT Authentication Tutorial: Using Angular HttpClient with Node & Express.js Server