Build Ionic 4 Cordova and Angular 8 CRUD Mobile App

By Digamber Rawat Last updated on
A step by step Ionic 4 Cordova tutorial, In this tutorial, we will learn how to create a CRUD (Create, Read, Update, Delete) Mobile app (Android/iOS) with Ionic 4 and Angular 8

In this tutorial, we will learn how to create a hybrid mobile app using Ionic/Angular 8 with Cordova which will support both Android/iOS. Our music app will allow our users to add a song, edit or update a song or view a song list.

Before we begin, we should always remember that we must use the latest Ionic 4 Cordova and Angular 8 version to avoid compatibility problems.

Prerequisite

You need to be familiar with the following tools and frameworks to understand this tutorial.

  • Node
  • Express
  • MongoDB
  • Ionic 4
  • Cordova
  • Angular 8
  • Angular 8 CLI
  • Text Editor

To set up Node.js on your system, you need to download the latest version of Node from here. You can also follow this tutorial to install Node js on your system.

Ionic 4 Cordova Environment Setup

Run the following command to install Ionic 4 Cordova globally in your system.

sudo npm install -g cordova ionic

You can verify the Ionic CLI version by running the below command.

ionic -v

# 5.4.6

Use following command to update Ionic 4 and Cordova.

sudo npm update -g cordova ionic

Angular CLI can also be updated by using the below command.

sudo npm install -g @angular/cli

Create Ionic 4 Cordova Project with Angular 8

To create the Ionic 4 CRUD mobile app, we need to enter the following command in Ionic Angular CLI.

ionic start ionic-angular-crud-app --type=angular

Choose Ionic template from the Ionic ready-made 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

Get inside the Ionic 4 Cordova mobile CRUD app’s project folder.

cd ionic-angular-crud-app

Next, start the Ionic 4 CRUD mobile app in both iOS and Android mode in the browser. First, Run the below command to install lab mode as a development dependency.

npm i @ionic/lab --save-dev

Then, run the command in the terminal. It will open the Ionic CRUD mobile app in the browser.

ionic serve -l

Ionic 4 Cordova Angular 9 CRUD App

Configure Angular 8 Routes in Ionic 4 App

To configure routes in the Ionic 4 Cordova app, we need to generate pages, run the following command in the terminal.

ng generate page add-song

ng generate page edit-song

We created add-song and edit-song pages, in Ionic 4/Angular app’s home page we will render the songs list. Go to the src/app/app-routing.ts file and include the following code.

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: 'add-song',
    loadChildren: () => import('./add-song/add-song.module').then(m => m.AddSongPageModule)
  },
  {
    path: 'edit-song/:id',
    loadChildren: () => import('./edit-song/edit-song.module').then(m => m.EditSongPageModule)
  },
];

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

export class AppRoutingModule { }

Create Node/Express Server

Now we will create a backend server to manage the data for our Ionic 4/Angular 8 CRUD mobile app. We will set up a backend server with the help of Node, Express and MongoDB. We will create REST APIs for Create, Read, Update and Delete songs data and store the data in the MongoDB database.

Create a folder in the root of the Ionic 4/Angular project and name it backend and then get inside this folder.

Run the following command from the root of your Ionic project.

mkdir backend && cd backend

Create the specific package.json for the node/express server.

npm init -y

Install following NPM packages.

npm install body-parser cors express mongoose --save

Install nodemon npm package as a development dependency to avoid re-starting the server every time we make the changes in the server files.

npm install nodemon --save-dev

Create database folder and also create db.js file in the backend folder’s root then paste the following code in it.

module.exports = {
  db: 'mongodb://localhost:27017/node_db'
};

Create model folder and also create Song.js file in the backend folder’s root then add the following code in it.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

let Song = new Schema({
  song_name: {
    type: String
  },
  artist: {
    type: String
  }
}, {
  collection: 'songs'
})

module.exports = mongoose.model('Song', Song)

Next, create REST APIs for creating, reading, updating and deleting song data for our Ionic 4 CRUD mobile app. We will take help of express js middlewares, and later we will learn how to consume REST APIs in Ionic4/Angular app.

Create routes folder and also create song.route.js file in the backend folder’s root then add the following code in it.

const express = require('express');
const app = express();
const songRoute = express.Router();

let SongModel = require('../model/Song');

// Add Song
songRoute.route('/create-song').post((req, res, next) => {
  SongModel.create(req.body, (error, data) => {
    if (error) {
      return next(error)
    } else {
      res.json(data)
    }
  })
});

// Get all songs
songRoute.route('/').get((req, res) => {
  SongModel.find((error, data) => {
    if (error) {
      return next(error)
    } else {
      res.json(data)
    }
  })
})

// Get single song
songRoute.route('/get-song/:id').get((req, res) => {
  SongModel.findById(req.params.id, (error, data) => {
    if (error) {
      return next(error)
    } else {
      res.json(data)
    }
  })
})


// Update song
songRoute.route('/update-song/:id').put((req, res, next) => {
  SongModel.findByIdAndUpdate(req.params.id, {
    $set: req.body
  }, (error, data) => {
    if (error) {
      return next(error);
      console.log(error)
    } else {
      res.json(data)
      console.log('Song successfully updated!')
    }
  })
})

// Delete song
songRoute.route('/delete-song/:id').delete((req, res, next) => {
  SongModel.findByIdAndRemove(req.params.id, (error, data) => {
    if (error) {
      return next(error);
    } else {
      res.status(200).json({
        msg: data
      })
    }
  })
})

module.exports = songRoute;

In the next step we will configure node/express server, create app.js file in the backend folder’s root and add the given below code inside of it.

let express = require('express'),
  path = require('path'),
  mongoose = require('mongoose'),
  cors = require('cors'),
  bodyParser = require('body-parser'),
  dataBaseConfig = require('./database/db');

// Connecting mongoDB
mongoose.Promise = global.Promise;
mongoose.connect(dataBaseConfig.db, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false
}).then(() => {
  console.log('Database connected sucessfully ')
},
  error => {
    console.log('Could not connected to database : ' + error)
  }
)

const songRoute = require('./routes/song.route')

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));
app.use(cors());

// RESTful API root
app.use('/api', songRoute)

// PORT
const port = process.env.PORT || 3000;

app.listen(port, () => {
  console.log('PORT Connected on: ' + port)
})

// Find 404 and hand over to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// Find 404 and hand over to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  console.error(err.message);
  if (!err.statusCode) err.statusCode = 500;
  res.status(err.statusCode).send(err.message);
});

Go to backend > package.json file and update the main: "index.js" name to main: "app.js" and you are ready to start the backend server. Run the below command while staying in the backend folder.

nodemon server

Start MongoDB server:
Open the terminal and run the below command in it to start the mongoDB server.

mongod

REST API URL – http://localhost:3000/api

Method API url
GET All /api
GET Single /api/get-song/id
POST /api/create-song
PUT /api/update-song/id
DELETE /api/delete-song/id

Create Ionic 4 Angular 8 API Service

We will take the help of Ionic 4/Angular 8 Service to manage REST API in our CRUD mobile app. To make API calls, we need to import HttpClientModule service in the Ionic 4 Angular project.

Head over to src/app/app.module.ts then import and register `HttpClientModule`.

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [...],
  entryComponents: [...],
  imports: [
    HttpClientModule
  ],
  providers: [...],
  bootstrap: [...]
})

export class AppModule { }

For type checking, we need to create a Song class. Generate a shared folder then create song.ts file in it. Include the given below code in it to define the song data type.

export class Song {
    _id: number;
    song_name: string;
    artist: string;
}

Run the following command to create Ionic 4/Angular 8 Service for handling REST API calls inside the shared folder:

ng generate service shared/song

Next, place the following code in shared/song.service.ts:

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

@Injectable({
  providedIn: 'root'
})

export class SongService {

  httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
  };

  constructor(private http: HttpClient) { }

  addSong(song: Song): Observable<any> {
    return this.http.post<Song>('http://localhost:3000/api/create-song', song, this.httpOptions)
      .pipe(
        catchError(this.handleError<Song>('Add Song'))
      );
  }

  getSong(id): Observable<Song[]> {
    return this.http.get<Song[]>('http://localhost:3000/api/get-song/' + id)
      .pipe(
        tap(_ => console.log(`Song fetched: ${id}`)),
        catchError(this.handleError<Song[]>(`Get Song id=${id}`))
      );
  }

  getSongList(): Observable<Song[]> {
    return this.http.get<Song[]>('http://localhost:3000/api')
      .pipe(
        tap(songs => console.log('Songs fetched!')),
        catchError(this.handleError<Song[]>('Get Songs', []))
      );
  }

  updateSong(id, song: Song): Observable<any> {
    return this.http.put('http://localhost:3000/api/update-song/' + id, song, this.httpOptions)
      .pipe(
        tap(_ => console.log(`Song updated: ${id}`)),
        catchError(this.handleError<Song[]>('Update Song'))
      );
  }

  deleteSong(id): Observable<Song[]> {
    return this.http.delete<Song[]>('http://localhost:3000/api/delete-song/' + id, this.httpOptions)
      .pipe(
        tap(_ => console.log(`Song deleted: ${id}`)),
        catchError(this.handleError<Song[]>('Delete Song'))
      );
  }


  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.error(error);
      console.log(`${operation} failed: ${error.message}`);
      return of(result as T);
    };
  }
}

To make the Http request we imported HttpClientModule in AppModule, now import RxJS operators to send the HTTP request across the server and get the response. Import observable, of, catchError and tap along with HttpClient and HttpHeaders.

Ionic 4/Angular 8 Display Data List & Delete Data

Now, we will display data list in Ionic 4 mobile app. Open home/home.page.ts file and add the following code in it.

import { Component, OnInit } from '@angular/core';
import { SongService } from './../shared/song.service';

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

export class HomePage implements OnInit {
  Songs: any = [];

  constructor(
    private songService: SongService
  ) {
  }

  ngOnInit() { }

  ionViewDidEnter() {
    this.songService.getSongList().subscribe((res) => {
      console.log(res)
      this.Songs = res;
    })
  }

  deleteSong(song, i) {
    if (window.confirm('Do you want to delete user?')) {
      this.songService.deleteSong(song._id)
        .subscribe(() => {
          this.Songs.splice(i, 1);
          console.log('Song deleted!')
        }
        )
    }
  }
}

Import the Angular 8 service and inject into the constructor it will allow us to consume the REST APIs and render the data into the Ionic 4 view. We use the ionViewDidEnter() page life cycle hook this hook will update the data in the Ionic view if the data is updated in the database. We also declared the deleteSong() function it helps in removing the song data from the Ionic 4 as well as the mongoDB database.

Next, open the home/home.page.html file and include the following code in it.

<ion-header>
  <ion-toolbar>
    <ion-title>
      Ionic Music App
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-list class="ios list-ios hydrated">
    <ion-list-header class="ios hydrated">
      Song List
    </ion-list-header>

    <ion-item *ngFor="let song of Songs" class="item-label item ios in-list ion-focusable hydrated">
      <ion-label class="sc-ion-label-ios-h sc-ion-label-ios-s ios hydrated">
        <h2>{{song.song_name}}</h2>
        <h3>{{song.artist}}</h3>
      </ion-label>

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


  <!-- fab placed to the bottom start -->
  <ion-fab vertical="bottom" horizontal="end" slot="fixed" routerLink="/add-song">
    <ion-fab-button>
      <ion-icon name="add"></ion-icon>
    </ion-fab-button>
  </ion-fab>
</ion-content>

Here, we used the Ionic HTML to display the data list in the Ionic view we are showing the data with the help of Angular’s *ngFor directive. Declare the routerLink directive and pass the edit-song route to navigate to the edit page.

To know more about Ionic’s UI components check out here.

Add Data in Ionic 4

To add the data, we need to import and register FormsModule and ReactiveFormsModule in page’s module. Now, we need to remember that we have to import these Angular 8 form services in every page’s module rather than using it globally in the app.module.ts file.

Open add-song.module.ts file and add the following code.

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

@NgModule({
  imports: [
    FormsModule,
    ReactiveFormsModule
  ]
})

Open add-song.page.ts file and add the following code.

import { Component, OnInit, NgZone } from '@angular/core';
import { SongService } from './../shared/song.service';
import { Router } from '@angular/router';
import { FormGroup, FormBuilder } from "@angular/forms";


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

export class AddSongPage implements OnInit {
  songForm: FormGroup;

  constructor(
    private songAPI: SongService,
    private router: Router,
    public fb: FormBuilder,
    private zone: NgZone
  ) {
    this.songForm = this.fb.group({
      song_name: [''],
      artist: ['']
    })
  }

  ngOnInit() { }

  onFormSubmit() {
    if (!this.songForm.valid) {
      return false;
    } else {
      this.songAPI.addSong(this.songForm.value)
        .subscribe((res) => {
          this.zone.run(() => {
            console.log(res)
            this.songForm.reset();
            this.router.navigate(['/home']);
          })
        });
    }
  }
}

Open add-song.page.html file and add the following code.

<ion-header>
  <ion-toolbar class="ios hydrated">
    <ion-buttons slot="start">
      <ion-back-button defaultHref="home"></ion-back-button>
    </ion-buttons>
    <ion-title class="ios title-ios hydrated">Add Song</ion-title>
  </ion-toolbar>
</ion-header>


<ion-content>
  <ion-list lines="full" class="ion-no-margin ion-no-padding ios list-ios list-lines-full list-ios-lines-full hydrated">
    <form [formGroup]="songForm" (ngSubmit)="onFormSubmit()">
      <ion-item>
        <ion-label position="floating">Name</ion-label>
        <ion-input formControlName="song_name" type="text" required></ion-input>
      </ion-item>

      <ion-item>
        <ion-label position="floating">Artist</ion-label>
        <ion-input formControlName="artist" 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-content>

Ionic 4 Edit Data

To edit the data you need to open the edit-song.module.ts file and add the following code in it.

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

@NgModule({
  imports: [
    FormsModule,
    ReactiveFormsModule
  ]
})

Next, open the edit-song.page.ts file and add the following code inside of it.

import { Component, OnInit } from '@angular/core';
import { SongService } from './../shared/song.service';
import { ActivatedRoute, Router } from "@angular/router";
import { FormGroup, FormBuilder } from "@angular/forms";

@Component({
  selector: 'app-edit-song',
  templateUrl: './edit-song.page.html',
  styleUrls: ['./edit-song.page.scss'],
})
export class EditSongPage implements OnInit {

  updateSongForm: FormGroup;
  id: any;

  constructor(
    private songAPI: SongService,
    private actRoute: ActivatedRoute,
    private router: Router,
    public fb: FormBuilder
  ) {
    this.id = this.actRoute.snapshot.paramMap.get('id');
  }

  ngOnInit() {
    this.getSongData(this.id);
    this.updateSongForm = this.fb.group({
      song_name: [''],
      artist: ['']
    })
  }

  getSongData(id) {
    this.songAPI.getSong(id).subscribe(res => {
      this.updateSongForm.setValue({
        song_name: res['song_name'],
        artist: res['artist']
      });
    });
  }

  updateForm() {
    if (!this.updateSongForm.valid) {
      return false;
    } else {
      this.songAPI.updateSong(this.id, this.updateSongForm.value)
        .subscribe((res) => {
          console.log(res)
          this.updateSongForm.reset();
          this.router.navigate(['/home']);
        })
    }
  }

}

Next, open the edit-song.page.html file and add the following code inside of it.

<ion-header>
  <ion-toolbar class="ios hydrated">
    <ion-buttons slot="start">
      <ion-back-button defaultHref="home"></ion-back-button>
    </ion-buttons>
    <ion-title class="ios title-ios hydrated">Add Song</ion-title>
  </ion-toolbar>
</ion-header>


<ion-content>
  <ion-list lines="full" class="ion-no-margin ion-no-padding ios list-ios list-lines-full list-ios-lines-full hydrated">
    <form [formGroup]="updateSongForm" (ngSubmit)="updateForm()">
      <ion-item>
        <ion-label position="floating">Song name</ion-label>
        <ion-input formControlName="song_name" type="text" required></ion-input>
      </ion-item>

      <ion-item>
        <ion-label position="floating">Artist</ion-label>
        <ion-input formControlName="artist" type="text" required>
        </ion-input>
      </ion-item>

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

Conclusion

Finally, we have completed Ionic 4/Cordova and Angular 8 tutorial. In this tutorial we learned how to create Ionic 4 Hybrid CRUD mobile app. We also learned how to create REST APIs with the help of Node/Express and save the data from the Ionic 4 frontend to MongoDB database. To compare your code with this tutorial, you can download the complete code from this Github repo.

Digamber Rawat
Digamber Rawat

Full stack developer with a passion for UI/UX design. I create beautiful and useful digital products to solve people’s problem and make their life easy.

Thanks for checking this tutorial out :) Let me know if you have any suggestions or issue related to this tutorial, or you want to request a new tutorial. Just shoot me a mail here.