How to use Ionic 4 NativeStorage to set and get the Data in Storage

How to use Ionic 4 NativeStorage to set and get the Data in Storage

In this Ionic 4 Storage tutorial, we'll learn how to use Ionic 4 NativeStorage to set and get the data in storage. Learn how to store data using Ionic 4 NativeStorage, we will learn how to store data on the local device in JSON or key-value pair format.

Today we will learn how to store data using Ionic 4 NativeStorage, We will learn how to store data on the local device in JSON or key-value pair format.

Storing data on a user’s device is an essential task for any dev, and it is needed nearly in every web or mobile app. A user might save any data on his/her device, be it a shopping cart, user profile, app settings, user sessions, etc.

Let’s start installing a new Ionic project.

Table of Contents

  1. Configure Ionic Project
  2. Setting up Native Storage in Ionic 4
  3. Implementing Storage in Ionic App
  4. Accessing Storage Methods
  5. Conclusion
1. Configure Ionic Project

Let’s install a new Ionic/Angular app, to begin with, this tutorial.

# Update Ionic CLI
sudo npm update -g ionic

# Create new Ionic app
ionic start ionic-storage blank --type=angular

# Enter inside project
cd ./ionic-storage

Run command to install lab mode as a dev-dependency for testing purpose.

npm i @ionic/lab --save-dev

Start Ionic Local Storage project.

ionic serve -l
2. Setting up Native Storage in Ionic 4

Run command to install Cordova’s nativestorage plugin.

ionic cordova plugin add cordova-plugin-nativestorage

Run command to install Ionic Native plugin for using Storage feature.

npm install @ionic-native/native-storage

To use Native storage plugin throughout the application, Import and register NativeStorage module in AppModule.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

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 { NativeStorage } from '@ionic-native/native-storage/ngx';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    StatusBar,
    SplashScreen,
    NativeStorage,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }
3. Implementing Storage in Ionic App

Ionic offers two ways to store data in the storage.

3.1 Storage in Ionic Cordova SQLite

Cordova’s sqlite storage plugin is used to save the data in key/value pairs & JSON format, we use Ionic’s storage module with Cordova’s cordova-sqlite-storage plugin.

In SQLite in Ionic 4 is used for native apps that work on mobile devices. The localStorage or IndexedDB is used to store data in Progressive Web apps and simply works on the browser. However, the best method is chosen depending on your platform and requirements.

3.2 Cordova Native Storage

Cordova’s cordova-plugin-nativestorage plugin provides faster and more data storage. It is suitable for Native storage for iOS, Android, and Windows.

In this tutorial, we will learn to work with Cordova’s Native storage with the cordova-plugin-nativestorage plugin.

Let’s begin installing Ionic/Angular project, Run the following command to create a new Ionic 4 application.

To access Native Storage methods, we need to Import the NativeStorage plugin in the home template and inject it in the constructor.

import { Component } from '@angular/core';
import { NativeStorage } from '@ionic-native/native-storage/ngx';

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

export class HomePage {

  constructor(private nativeStorage: NativeStorage) { }

}

4. Accessing Storage Methods

Now we can quickly get and set the data with the help of Native Storage methods.

4.1 Storing values

Let’s start setting up some data in the local storage using the nativeStorage setItem method.

To store value in local storage.

setItem(storageRef: string, value: any)
this.nativeStorage.setItem('myitem', {property: 'value', anotherProperty: 'anotherValue'})
  .then(
    () => console.log('Stored item!'),
    error => console.error('Error storing item', error)
  );

4.2 Get values

Let’s start retrieving data from the local storage using the nativeStorage getItem method.

To get value from local storage.

getItem(storageRef: string, value: any)
this.nativeStorage.getItem('myitem')
  .then(
    data => console.log(data),
    error => console.error(error)
  );

4.3 Get All Keys

Let’s start retrieving data from the local storage using the nativeStorage getItem method.

this.nativeStorage.keys()
   .then(
     data => console.log(data),
     error => console.error(error)
    );

4.4 Remove Value

To remove value from storage use the following method.

this.nativeStorage.remove('myitem')
.then(
  data => console.log(data),
  error => console.error(error)
);

4.5 Removing All Stored Values

To remove all stored values from storage use the given below method.

this.nativeStorage.remove('myitem')
.then(
  data => console.log(data),
  error => console.error(error)
);
5. Conclusion

Finally, we completed Ionic 4 Storage tutorial with in this tutorial we learned how to use NativeStorage to set and get the data in storage.

How to set up Firebase Realtime Database in Ionic 4 and Angular 8 App?

How to set up Firebase Realtime Database in Ionic 4 and Angular 8 App?

In this Ionic 4 Firebase tutorial, you'll learn step by step how to set up Firebase Realtime Database in Ionic 4 and Angular 8 App. Firebase is a popularly known Google product and Its a NoSQL Realtime Database.

In this Ionic 4 Firebase tutorial, we are going to look at step by step how to set up Firebase Realtime Database in Ionic 4/Angular 8 project.

Firebase is a popularly known Google product and Its a NoSQL Realtime Database. Working with Firebase is easy, It doesn’t make its user to lost in its dashboard due to its superb User Experience. Firebase offers top-notch features for building web and mobile applications swiftly:

  • Cloud storage
  • Realtime update
  • Easy A/B Testing
  • Analytics Monitoring
  • Authentication support
  • Easy Server management
  • Single-page app hosting
  • Real-time communication
  • Hosting and cloud storage
  • Push notifications support
  • Google Cloud IoT tools Integration support

Firebase offers two services:

Cloud Firestore: It’s a modern Real-time NoSQL database with auto-scaling and more robust queries.

Real-time Database: It allows us to build an app which needs to be updated at real-time. e.g., stock market app, sports app, live chat app etc.

In this tutorial we will focus on Firebase Real-time Database.

Table of Contents

  1. Create Firebase Account
  2. Create Ionic 4/Angular Project
  3. Install Firebase Package in Ionic 4/Angular App
  4. Configure Firebase Config Keys in Ionic 4
  5. Import and Register Firebase in AppModule
  6. Conclusion
1. Create Firebase Account

Visit console.firebase.google.com and sign in using your Gmail account.

Click on the “create a project” button then click on continue button.

Next, click on the web icon as shown in the screenshot.

Next, add Firebase to your web app. Enter the app’s nickname and then click on the next button.

It will take you to the screen where you will see Firebase configuration, copy the red marked Firebase configuration keys keep it in the notepad or something else. You will need these keys to register in your Ionic 4/Angular 8 project.

Next, we will click on the “database” from the left side navbar. Then, look for Realtime Database and click on the “create database” button.

It will open the security rules modal popover, select “start in test mode” option. Remember we are setting up these rules fro testing purpose. In real world app be careful about database rules.

Now, we are all set to use the Firebase Real-time Database.

2. Create Ionic 4/Angular Project

Run the following command to generate a new Ionic 4/Angular project.

ionic start ionic-firebase-setup --type=angular

Choose blank or which ever template you would like to choose from the Ionic’s template list.

? Starter template: 
  tabs         | A starting project with a simple tabbed interface 
  sidemenu     | A starting project with a side menu with navigation in the content area 
❯ blank        | A blank starter project 
  my-first-app | An example application that builds a camera with gallery 
  conference   | A kitchen-sink application that shows off all Ionic has to offer

Head over to the Ionic 4 Firebase project folder.

cd ionic-firebase-setup

Run the following command to install lab mode.

npm i @ionic/lab --save-dev

Start the Ionic 4 app.

ionic serve -l

3. Install Firebase Package in Ionic 4/Angular App

We need to install the Firebase library to set up Firebase in our Ionic 4/Angular app. Run the following command in the terminal.

npm install @angular/fire
4. Configure Firebase Config Keys in Ionic 4

In this step, we will register the Firebase config rules inside the
environment.prod.ts (production environment) and environment.ts file, you can find these files in the src > environments folder.

Add the following code inside the environment.prod.ts file.

export const environment = {
  production: true,
  firebaseConfig: {
    apiKey: "<your-api-key>",
    authDomain: "<your-auth-domain>",
    databaseURL: "<your-database-url>",
    projectId: "<your-cloud-firestore-project>",
    storageBucket: "<your-storage-bucket>",
    messagingSenderId: "<your-sender-id>",
    appId: "<your-app-id>",
    measurementId: "<your-measurement-id>"
  }
};

Place the following code inside the environment.ts file.

export const environment = {
  production: false,
  firebaseConfig: {
    apiKey: "<your-api-key>",
    authDomain: "<your-auth-domain>",
    databaseURL: "<your-database-url>",
    projectId: "<your-cloud-firestore-project>",
    storageBucket: "<your-storage-bucket>",
    messagingSenderId: "<your-sender-id>",
    appId: "<your-app-id>",
    measurementId: "<your-measurement-id>"
  }
};
5. Import and Register Firebase in AppModule

Lastly, go to app.module.ts file. Here import and register Firebase services along with that also inject Firebase config keys with the AngularFireModule.initializeApp() method.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

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';

//  firebase imports, remove what you don't require
import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireDatabaseModule } from '@angular/fire/database';
import { AngularFireStorageModule } from '@angular/fire/storage';

// environment
import { environment } from '../environments/environment';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFireAuthModule,
    AngularFireDatabaseModule,
    AngularFireStorageModule
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

6. Conclusion

That’s it for now, finally we have learned how to set up Firebase in an Ionic 4/Angular 8 app. Now, you can connect your Ionic app with Firebase Realtime database and enjoy building it.

How to Build an Ionic 5 CRUD App with SQLite Database

How to Build an Ionic 5 CRUD App with SQLite Database

In this Ionic 5 SQLite Database tutorial, we will learn how to create Ionic 5 Angular CRUD application and implement SQLite Native plugin to store the data in the SQLite Database. We will create the Create, Read, Update and Delete operation to manage the data in the database. Learn to load the dummy data from the sql database file using HttpClient service.

In this tutorial, we will learn how to create Ionic 5 Angular CRUD application and implement SQLite Native plugin to store the data in the SQLite Database. We will create the Create, Read, Update and Delete operation to manage the data in the database. Moreover, we will also learn to load the dummy data from the sql database file using HttpClient service.

SQLite is an open-source relational database i.e. used to perform database operations on android devices such as storing, manipulating or retrieving persistent data from the database. It is embedded in android by-default. So, there is no need to perform any database setup or administration task.

Here, we are going to see the example of sqlite to store and fetch the data. Data is displayed in the logcat. For displaying data on the spinner or listview, move to the next page. Storing data on a user device is an essential topic that we are going to cover in this Ionic 4 hybrid mobile app tutorial.

Table of Contents

  • Prerequisite
  • Install New Ionic 5 Application
  • Adding Fake SQL Data
  • Configure Routes
  • Install & Configure Packages – sqlite, sqlite-porter, cordova-sqlite-storage
  • Create CRUD Service with SQLite
  • Implement Reactive Forms in Ionic 5
  • Add, Display & Delete Data from SQLite Database
  • Update Data from SQLite Database
  • Run Ionic App in Device
  • Conclusion
Ionic 5 SQLite Database Example

Prerequisite

We must have following tools, frameworks, and packages to get started with this tutorial.

  • Latest Node
  • Ionic CLI
  • Ionic 5
  • Angular
  • Firebase FCM
  • Postman
  • Text Editor
  • @ionic-native/sqlit
  • Cordova SQLite Storage

Follow this tutorial on: How to Download and Install Node.js and npm

Install New Ionic 4 Application

We are going to work with Ionic 4 Native SQLite plugin, and It is a robust plugin for storing the data and primarily used with Ionic framework. It works on the same SQL pattern tables and rows. We write SQL queries to fetch the data from the database. It works on the user’s device memory, and the good thing is It doesn’t have storage limitation to store the data.

Install the latest version of Ionic CLI and Cordova globally installed on your device, run the below command.

sudo npm install -g cordova ionic

Run the following command to verify the Ionic CLI version.

ionic -v

# 5.4.15

Run the following command to create a brand new blank Ionic 4 Angular project.

ionic start ionic-sqlite-app blank --type=angular

Go inside the Ionic project directory.

cd ionic-sqlite-app

Start the app in the browser.

ionic serve --lab
Adding Fake SQL Data

Let’s add some dummy data, and we can add even data in JSON format; however, in this article, i will teach how to add SQL data.

Create a SQL file inside assets/dump.sql folder and insert the following data in it.

CREATE TABLE IF NOT EXISTS songtable(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    artist_name TEXT, 
    song_name TEXT
);

INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (1, 'Justin Bieber', 'Yummy');
INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (2, 'Jonas Brothers', 'What A Man Gotta Do');
INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (3, 'Life Is Good', 'Future');
INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (4, 'Lauv', 'Tattoos Together');
INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (5, 'Heavy Steppers', 'Whateva');
INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (6, 'DigDat 2020', 'Ei8ht Mile');
INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (7, 'Blackbear', 'me & ur ghost');
INSERT or IGNORE INTO songtable(id, artist_name, song_name) VALUES (8, 'Hailee Steinfeld', 'Wrong Direction');

As you can see, we defined the SQL table, in which there is an ID which is set to auto-increment. The artist_name and song_name values belong to the string data type.

Configure Routes

Now, we require to generate a page. On this page, we show the song data, and a user can perform the update operation as well. Secondly, we will make the small change for the song route in the app routing file.

Run the command from terminal to create the page.

ng generate page song

Open the app-routing.module.ts file and add the following code in it.

// app-routing.module.ts

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

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: () => import('./home/home.module').then( m => m.HomePageModule)},
  {
    path: 'song/:id',
    loadChildren: () => import('./song/song.module').then( m => m.SongPageModule)
  }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})

export class AppRoutingModule { }

We have completed almost every configuration required for this tutorial; let’s start writing the core logic for storing data in the SQLite database.

Install & Configure Packages – sqlite, sqlite-porter, cordova-sqlite-storage

Run the following commands to install the required packages such as sqlite-porter, cordova-sqlite-storage, @ionic-native/sqlite.

$ npm install @ionic-native/sqlite
$ ionic cordova plugin add cordova-sqlite-storage

$ npm install @ionic-native/sqlite-porter
$ ionic cordova plugin add uk.co.workingedge.cordova.plugin.sqliteporter

This SQLite Porter plugin is used to import and export to and from a SQLite database using either SQL or JSON.

Next, import and register the above plugins in the application’s main app module file, this will allow us to access all the methods and services of the SQLite Database.

Don’t forget to add the HttpClientModule as we will be making the HTTP request to render the data locally from the SQL data file.

Open app.module.ts file and place the following code inside of it.

// app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

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';

// plugins
import { SQLite } from '@ionic-native/sqlite/ngx';
import { HttpClientModule } from '@angular/common/http';
import { SQLitePorter } from '@ionic-native/sqlite-porter/ngx';

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

export class AppModule {}
Create CRUD Service with SQLite

Run the following command to create a song class file.

ng g class services/song

Define the data types for the Song object in services/song.ts file.

export class Song {
  id: number;
  artist_name: string;
  song_name: string;
}

Angular service keeps all the essential functions and methods at one place that we don’t want to define in our application repetitively. Create a service file inside the service folder by using the command below.

ng generate service services/db

Open the services/db.service.ts file replace with the following code.

// db.service.ts

import { Injectable } from '@angular/core';
import { Platform } from '@ionic/angular';
import { Song } from './song';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { SQLitePorter } from '@ionic-native/sqlite-porter/ngx';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite/ngx';

@Injectable({
  providedIn: 'root'
})

export class DbService {
  private storage: SQLiteObject;
  songsList = new BehaviorSubject([]);
  private isDbReady: BehaviorSubject<boolean> = new BehaviorSubject(false);

  constructor(
    private platform: Platform, 
    private sqlite: SQLite, 
    private httpClient: HttpClient,
    private sqlPorter: SQLitePorter,
  ) {
    this.platform.ready().then(() => {
      this.sqlite.create({
        name: 'positronx_db.db',
        location: 'default'
      })
      .then((db: SQLiteObject) => {
          this.storage = db;
          this.getFakeData();
      });
    });
  }

  dbState() {
    return this.isDbReady.asObservable();
  }

  fetchSongs(): Observable<Song[]> {
    return this.songsList.asObservable();
  }

    // Render fake data
    getFakeData() {
      this.httpClient.get(
        'assets/dump.sql', 
        {responseType: 'text'}
      ).subscribe(data => {
        this.sqlPorter.importSqlToDb(this.storage, data)
          .then(_ => {
            this.getSongs();
            this.isDbReady.next(true);
          })
          .catch(error => console.error(error));
      });
    }

  // Get list
  getSongs(){
    return this.storage.executeSql('SELECT * FROM songtable', []).then(res => {
      let items: Song[] = [];
      if (res.rows.length > 0) {
        for (var i = 0; i < res.rows.length; i++) { 
          items.push({ 
            id: res.rows.item(i).id,
            artist_name: res.rows.item(i).artist_name,  
            song_name: res.rows.item(i).song_name
           });
        }
      }
      this.songsList.next(items);
    });
  }

  // Add
  addSong(artist_name, song_name) {
    let data = [artist_name, song_name];
    return this.storage.executeSql('INSERT INTO songtable (artist_name, song_name) VALUES (?, ?)', data)
    .then(res => {
      this.getSongs();
    });
  }

  // Get single object
  getSong(id): Promise<Song> {
    return this.storage.executeSql('SELECT * FROM songtable WHERE id = ?', [id]).then(res => { 
      return {
        id: res.rows.item(0).id,
        artist_name: res.rows.item(0).artist_name,  
        song_name: res.rows.item(0).song_name
      }
    });
  }

  // Update
  updateSong(id, song: Song) {
    let data = [song.artist_name, song.song_name];
    return this.storage.executeSql(`UPDATE songtable SET artist_name = ?, song_name = ? WHERE id = ${id}`, data)
    .then(data => {
      this.getSongs();
    })
  }

  // Delete
  deleteSong(id) {
    return this.storage.executeSql('DELETE FROM songtable WHERE id = ?', [id])
    .then(_ => {
      this.getSongs();
    });
  }
}

Import required API at the top part of the database service file.

The Song class is imported, which allows us to define the data type for the Song object.

The SQLite database is created when the app is ready using the Platform API. In response, we are also loading the dummy song data by calling the getFakeData() method.

To get the current database state, we imported RxJS BehaviorSubject and Observable properties and can extract the current database state by merely subscribing to them.

The getFakeData() method renders the fake data from the dump.sql file. We access the dummy data by making the Http GET request and then subscribe to the response and also setting the database state to true.

The executeSql() function allows us to make SQL queries to interacts with the SQL database, and we are using it to Get, Send, Update, or Delete the data from the storage.

Implement Reactive Forms in Ionic 4

Working with Reactive Forms in Ionic requires to import and register ReactiveFormsModule API in every Ionic page that we are going to work with. For example, in this tutorial, we will need the form in the Home and Song page to add or update the data.

Open your home.module.ts and song.module.ts files and import ReactiveFormsModule in the header part and register this API in the imports array.

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ReactiveFormsModule,
    FormsModule
  ]
})
Add, Display & Delete Data from SQLite Database

Now, we will learn how to fetch, add and remove data from the SQLite database. Open the home.page.ts file and import the following services in the header section.

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from "@angular/forms";
import { DbService } from './../services/db.service';
import { ToastController } from '@ionic/angular';
import { Router } from "@angular/router";

The FormGroup and FormBuilder are used to create the Reactive Form to get the user entered data.

  constructor(
    private db: DbService,
    public formBuilder: FormBuilder,
    private toast: ToastController,
    private router: Router
  ) { }

Inject the services in the constructor. Define Reactive Form by declaring the mainForm: FormGroup, to display the song data, also declare Data array.

mainForm: FormGroup;
Data: any[] = []

To show the data, we need to use the DbService that we injected in the constructor. Set the method in the ngOnInit life cycle hook.

Check the database state if its true then render the song list using the fetchSongs() method.

The mainForm is the main object that initiates the main form to add the data in the SQLite database.

ngOnInit() {
  this.db.dbState().subscribe((res) => {
    if(res){
      this.db.fetchSongs().subscribe(item => {
        this.Data = item
      })
    }
  });

  this.mainForm = this.formBuilder.group({
    artist: [''],
    song: ['']
  })
}

The storeData() method stores the data in the storage when a user clicks on the submit button.

storeData() {
  this.db.addSong(
    this.mainForm.value.artist,
    this.mainForm.value.song
  ).then((res) => {
    this.mainForm.reset();
  })
}

Here is the method to delete the data from the SQL database; we also used the Ionic Toast service to display the data delete the message when data is removed.

deleteSong(id){
  this.db.deleteSong(id).then(async(res) => {
    let toast = await this.toast.create({
      message: 'Song deleted',
      duration: 2500
    });
    toast.present();      
  })
}

Here is the completed code in the src/home.page.ts file.

// home.page.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from "@angular/forms";
import { DbService } from './../services/db.service';
import { ToastController } from '@ionic/angular';
import { Router } from "@angular/router";

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

export class HomePage implements OnInit {
  mainForm: FormGroup;
  Data: any[] = []

  constructor(
    private db: DbService,
    public formBuilder: FormBuilder,
    private toast: ToastController,
    private router: Router
  ) { }

  ngOnInit() {
    this.db.dbState().subscribe((res) => {
      if(res){
        this.db.fetchSongs().subscribe(item => {
          this.Data = item
        })
      }
    });

    this.mainForm = this.formBuilder.group({
      artist: [''],
      song: ['']
    })
  }

  storeData() {
    this.db.addSong(
      this.mainForm.value.artist,
      this.mainForm.value.song
    ).then((res) => {
      this.mainForm.reset();
    })
  }

  deleteSong(id){
    this.db.deleteSong(id).then(async(res) => {
      let toast = await this.toast.create({
        message: 'Song deleted',
        duration: 2500
      });
      toast.present();      
    })
  }

}

Open the home.page.html file and place the following code inside of it. It contains the form and song data list.

// home.page.html

<ion-header>
  <ion-toolbar>
    <ion-title>Ionic 4 SQLite CRUD Example</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-list lines="full">
    <form [formGroup]="mainForm" (ngSubmit)="storeData()">
      <ion-item>
        <ion-label position="floating">Artist name</ion-label>
        <ion-input formControlName="artist" type="text" required></ion-input>
      </ion-item>

      <ion-item>
        <ion-label position="floating">Song name</ion-label>
        <ion-input formControlName="song" type="text" required>
        </ion-input>
      </ion-item>

      <ion-row>
        <ion-col>
          <ion-button type="submit" color="primary" shape="full" expand="block">
            Add Song
          </ion-button>
        </ion-col>
      </ion-row>
    </form>
  </ion-list>

    <ion-list>
    <ion-list-header>
      Songs
    </ion-list-header>

    <ion-item lines="inset" *ngFor="let data of Data">
      <ion-label>
        <h5>{{data.artist_name}}</h5>
        <p>{{data.song_name}}</p>
      </ion-label>

      <div class="item-note" item-end>
        <ion-icon name="create" style="zoom:2.0" [routerLink]="['/song/', data.id]"></ion-icon>        
        <ion-icon name="trash" style="zoom:2.0" (click)="deleteSong(data.id)"></ion-icon>
      </div>
    </ion-item>
  </ion-list>
</ion-content>

We declared the click method and passed the deleteSong(id) method with the data-id.

Update Data from SQLite Database

Open the song.page.html file and replace with the following code.

// song.page.html

<ion-header>
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-back-button></ion-back-button>
    </ion-buttons>
    <ion-title>Edit Song</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-list lines="full">
    <form [formGroup]="editForm" (ngSubmit)="saveForm()">
      <ion-item>
        <ion-label position="floating">Artist name</ion-label>
        <ion-input formControlName="artist_name" type="text" required></ion-input>
      </ion-item>

      <ion-item>
        <ion-label position="floating">Song name</ion-label>
        <ion-input formControlName="song_name" type="text" required>
        </ion-input>
      </ion-item>

      <ion-row>
        <ion-col>
          <ion-button type="submit" color="primary" shape="full" expand="block">
            Update
          </ion-button>
        </ion-col>
      </ion-row>
    </form>
  </ion-list>
</ion-content>

Open the song.page.ts file and replace with the following code.

// song.page.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from "@angular/forms";
import { DbService } from './../services/db.service'
import { ActivatedRoute, Router } from "@angular/router";

@Component({
  selector: 'app-song',
  templateUrl: './song.page.html',
  styleUrls: ['./song.page.scss'],
})
export class SongPage implements OnInit {
  editForm: FormGroup;
  id: any;

  constructor(
    private db: DbService,
    private router: Router,
    public formBuilder: FormBuilder,
    private actRoute: ActivatedRoute
  ) {
    this.id = this.actRoute.snapshot.paramMap.get('id');

    this.db.getSong(this.id).then(res => {
      this.editForm.setValue({
        artist_name: res['artist_name'],
        song_name: res['song_name']
      })
    })
  }

  ngOnInit() {
    this.editForm = this.formBuilder.group({
      artist_name: [''],
      song_name: ['']
    })
  }

  saveForm(){
    this.db.updateSong(this.id, this.editForm.value)
    .then( (res) => {
      console.log(res)
      this.router.navigate(['/home']);
    })
  }

}

Set the form state when the Ionic page is loaded by using the getSong() method, it takes id as a parameter. We are extracting the song id using the ActivatedRoute API. The updateSong() method takes the song object and id to update the data in the SQLite database.

Run Ionic App in Device

To run the app in the Android device we need to use the following commands.

ionic cordova platform add android
ionic cordova run android --livereload
Conclusion

We have completed the Ionic 5 SQLite Database tutorial, in this tutorial, we learned how to create a CRUD application from scratch and store the data in the SQLite database. We learned to load the fake data from the SQL file locally using the HTTPClient API.

I hope you loved this tutorial and share it with others. You can get the complete code of this tutorial on this GitHub repository.

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!