Ionic is a cross-platform framework that uses web technologies like javascript, HTML, and CSS. Ionic is one of the popular mobile application development currently.

In this article, we will learn how to create a To-Do app using Ionic 5 with Angular and SQLite plugin.

The following image shows the version and CLI details used in the application.

ionic version details

The ionic To-Do app

We will create an ionic app with the blank template and add the SQLite plugin to it.

Creating the ionic app

To create a new Ionic application, open the command prompt/terminal, and run the following command.

We can also use an IDE like VS Code that provides a terminal window within the IDE.

ionic start toDoApp blank

The above CLI command generates a new ionic application with the name toDoApp in the current directory with a default blank template.

Choose Angular as the framework in the CLI option, as shown below.

Ionic 5 create new angular app

Adding SQLite plugin

Navigate inside the toDoApp directory and run the following commands.

The below command will add the SQLite plugin to our application.

npm install cordova-sqlite-storage
npm install @ionic-native/sqlite
ionic cap sync

Import the SQLite plugin

Update the app.module.ts file, as shown below.

We have to register the SQLite component as provider in order to use it inside our application.

import { SQLite } from '@ionic-native/sqlite/ngx';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [...],
  providers: [
    StatusBar,
    SplashScreen,
    SQLite,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
 bootstrap: [AppComponent]
})
export class AppModule {}

Creating the custom SQLite database service

Create a new database service by running the following command.

ng g s services/db

We have created an SQLite database service that will support the CRUD operation required for our To-Do application.

Ionic 5 To Do App with SQLite

Modify the content of the db.service.ts with the following code.

import { Injectable } from '@angular/core';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite/ngx';

export interface ToDoInterface {
  id: number;
  description: string;
  isDone: boolean;
}

@Injectable({
  providedIn: 'root'
})
export class DbService {

  private dbInstance: SQLiteObject;

  constructor(private sqlite: SQLite) { }

  async getAllToDos() {
    let todos: ToDoInterface[] = [];
    return this.sqlite.create({ name: 'data.db', location: 'default' }).then(
      (db) => {
        this.dbInstance = db;
        db.executeSql('CREATE TABLE IF NOT EXISTS '
          + 'TODO(id INTEGER PRIMARY KEY AUTOINCREMENT,'
          + ' description VARCHAR(50), isDone INTEGER(1))', [])
          .catch(e => console.log(e));
        todos = this.getAllRecords();
      }
    ).catch().then((e) => {
      console.log(e);
      return todos;
    });
  }

  private getAllRecords(): ToDoInterface[] {
    let todos: ToDoInterface[] = [];
    this.dbInstance.executeSql('select * from TODO', []).then(
      (res) => {
        for(var x=0; x<res.rows.length; x++)
          todos.push(res.rows.item(x));
      }
    ).catch(e => {
      console.log(e);
    });
    return todos;
  }

  async addToDo(description: string) {
    this.dbInstance.executeSql('insert into TODO(description, isDone) VALUES(?, ?)', [description, 0])
      .catch(e => console.log(e));
    return this.getAllRecords();
  }

  async updateToDo(id: number) {
    this.dbInstance.executeSql('UPDATE TODO SET ISDONE=1 WHERE ID=?', [id])
      .catch(e => console.log(e));
    return this.getAllRecords();
  }

  async deleteToDo(id: number) {
    this.dbInstance.executeSql('DELETE FROM TODO WHERE ID=?', [id])
      .catch(e => console.log(e));
    return this.getAllRecords();
  }
}
  • We have imported the SQLite and SQLiteObject modules. These modules support us to perform the database related CRUD operations with the SQLite database.
  • We have created a ToDoInterface typescript type, that holds the to-do items. It will have an id, description, and a boolean field to indicate the completion of the to-do item.
  • The DbService is registered as an angular service and decorated with @Injectable.
  • The constructor injects the SQLite instance that connects to the SQLite database.
  • The home.page.ts file invokes the getAllToDos() method that will initialize the SQLite database and also retrieves all available records from the database.
  • We are creating an SQLite database table called TODO if it is already not available. The table will have an auto-incremented ID, description field, and an integer column to indicate the completion of a to-do item.
  • We are also initializing SQLiteObject instance dbInstance, that can be used for other database operations like create/update/delete of to-do items.
  • addToDo() method creates a new to-do item with the description passed from UI.
  • updateToDo() method sets the isDone column value to 1 to indicate the completed to-do task.
  • deleteToDo() method deletes the to-do item with the ID passed from UI.

Using the service in the component

We need to update the app module and import and import the DbService and register it under the providers’ list.

import { DbService } from './services/db.service';

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

Updating the to-do app component

Change home.page.ts with the following content.

import { Component, OnInit } from '@angular/core';
import { DbService, ToDoInterface } from '../services/db.service';

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

  todos: ToDoInterface[];
  todoInput: string;

  constructor(private dbService: DbService) { }

  ionViewDidEnter() {
    this.todoInput = "";
    this.dbService.getAllToDos().then(data => this.todos = data);
  }

 addToDo(description: string) {
    this.dbService.addToDo(description).then(data => {
      this.todos = data;
      this.todoInput = "";
    });
  }

  deleteToDo(id: number) {
    this.dbService.deleteToDo(id)
      .then(data => this.todos = data);
  }

  doneToDo(id: number) {
    this.dbService.updateToDo(id)
      .then(data => this.todos = data);
  }
}
  • We have imported DbService and ToDoInterface, that we created in the previous section.
  • The constructor injects custom DbService to the component, which will help us perform the SQLite CRUD operation.
  • We have defined a todos array that holds all the to-do items fetched from the SQLite database.
  • The todoInput field will hold the user input with the help of two-way data binding, which gets persisted in the database.
  • We have also implemented ionViewDidEnter() ionic life cycle method. This method gets called after the view is loaded. We are retrieving all the available to-do items from the SQLite database.
  • The addToDo(), updateToDo() and deleteToDo() methods support the CRUD operations of the ionic application.

Creating the view

Update the HTML view of the app by updating the home.page.html with the below content.

<ion-header>
  <ion-toolbar>
    <ion-input name="todo-text" placeholder="Enter a To Do!!" type="text" required="true" maxlength="20" [(ngModel)]="todoInput">
    </ion-input>
    <ion-buttons slot="end">
      <ion-button fill="solid" color="success" size="medium" (click)="addToDo(todoInput)">
        <ion-icon name="add-sharp"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>
<ion-content>
  <div id="container">
    <ion-list>
      <ion-list-header>TO DO LIST</ion-list-header>
      <ion-item lines="inset" *ngFor="let todo of todos;index as slNo"
        [ngClass]="{done: todo.isDone, pending:  !todo.isDone}">
        <ion-label>
          <h4>{{slNo+1}}. {{todo.description}}</h4>
        </ion-label>
        <ion-button color="success" (click)="doneToDo(todo.id)" slot="end" *ngIf="!todo.isDone">
          <ion-icon name="checkmark-done-sharp"></ion-icon>
        </ion-button>
        <ion-button color="danger" (click)="deleteToDo(todo.id)" slot="end">
          <ion-icon name="trash-sharp"></ion-icon>
        </ion-button>
      </ion-item>
    </ion-list>
  </div>
</ion-content>
  • The <ion-header> is the header part of the app. The header will contain a text input field and a button. Users can enter the to-do text and click on + icon to save the to-do item.
  • We have used two-way data binding to set the todoInput filed’s value.
  • The app will iterate the available to-dos and display the to-do list.
  • The background color of the to-do item is decided based on the isDone flag.
  • The to-do items with isDone value false will show a button with the checkmark.
  • We also have a button with a delete icon, that deletes the to-do item from the list.

Add the given styles to the home.page.scss file.

We have added some basic styles to the ionic to-do application.

#container {
  text-align: center;
  left: 0;
  right: 0;
}

#container strong {
  font-size: 20px;
  line-height: 26px;
}

ion-content {
  --ion-background-color: rgba(247, 245, 166);
}
ion-item {
  color: black;
  align-items: center;
}

ion-button {
  align-self: flex-end;
}

ion-header {
  --ion-background-color: rgb(252, 101, 19);
  font-size: 20px;
}

ion-input {
  color: white;
}

.done {
  --ion-background-color: rgb(162, 250, 140) !important;
}

.pending {
  --ion-background-color: rgb(247, 137, 110) !important;
}

The done and pending CSS classes will give different background colors to the to-do items based on the isDone field value.

Testing the application

We will run the application with the help of the Android studio. We need to add the android platform to the ionic app.

To add the android platform, run the following command.

npx cap add android

Run the following command to build the project and run it on the connected native device/ emulator.

ionic build
npx cap sync
npx cap open android

To Do App Screens

We will get the below home page, that will have an input field where the user can input the To-Do description.

ionic 5 To do app

Once the user enters the to-do item description clicks on the + button, To-Do item will be created and populated under the To-Do List.

ionic 5 To do app

Every item on the list will have two buttons.

If the user clicks on the right marked button, the Todo item is marked as done, and the background color will become green.

ionic 5 To do app

If the user clicks on the delete button, the item gets deleted from the to-do list.

Conclusion

In this article, we learned how to create a simple To-Do app using Ionic 5 with angular.

We also learned how to add the android platform to the ionic app and test it with a connected android device/emulator.

This to-do application was a simple application that can be improved by adding additional features. We can add an option to update the To Do after saving it. We can also add some validation before saving the to-do item to the list.

The code is available on the GitHub.

You may also be interested in