[ionic 4] - SQLitePorter plugin is not installed

Hello,

I followed this tutorial: How to Build an Ionic 4 App with SQLite Database & Queries (And Debug It!) | Devdactic

I have a problem with the sqlitePorter plugin when I run this command on Visual Studio Code :

ionic serve --devapp

The application starts correctly on my mobile, but the following error suddenly appears in my console:

console.warn: Install the SQLitePorter plugin: ‘ionic cordova plugin add uk.co.workingedge.cordova.plugin.sqliteporter’
console.error: [plugin_not_installed error]

I do not really understand what happens because when I do “ionic cordova plugin ls”, the plugin is present.

Does anyone have an idea of ​​what might be going on, and how can I fix that?

Thank you in advance :slight_smile:

Does it shows on app start?

Sometimes plugins show these warnings during app start but it works after platform ready execution is complete.

In my case it was sqlite plugin but it works completely fine in app.

Also try doing

ionic cordova run android

When I use this command, the application runs without problems, but I do not have any data :confused:

Did you checked the sqlite plugin documentation?

How did you add data?

Thank you for your interest in my problem.
Here’s what I did:

seed.sql :

CREATE TABLE IF NOT EXISTS category(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,descriptions TEXT,img TEXT);
INSERT or IGNORE INTO categorie VALUES (1, 'Tâches Professionelle', 'Description', '');
INSERT or IGNORE INTO categorie VALUES (2, 'Tâches Personnelle', 'Description', '');
INSERT or IGNORE INTO categorie VALUES (3, 'Sport', 'Description', '');
 
CREATE TABLE IF NOT EXISTS task(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,description TEXT,categoryId INTEGER);
INSERT or IGNORE INTO task(id, name, description, categoryId) VALUES (1, 'Finir mon application', 'Description', 1);
INSERT or IGNORE INTO task(id, name, description, categoryId) VALUES (2, 'Ajouter des fonctionnalitées', 'Description', 1);
INSERT or IGNORE INTO task(id, name, description, categoryId) VALUES (3, 'Faire les courses', 'Description', 2);
INSERT or IGNORE INTO task(id, name, description, categoryId) VALUES (4, 'Test', 'Description', 2);
INSERT or IGNORE INTO task(id, name, description, categoryId) VALUES (5, 'Lorem Ipsum', 'Description', 3);
INSERT or IGNORE INTO task(id, name, description, categoryId) VALUES (6, 'Exemple', 'Description', 3);

database.service.ts :

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

export interface Cat {
  id: number,
  name: string,
  descriptions: any[],
  img: string
}

@Injectable({
  providedIn: 'root'
})
export class DatabaseService {
  private database: SQLiteObject;
  private dbReady: BehaviorSubject<boolean> = new BehaviorSubject(false);
 
  categories = new BehaviorSubject([]);
  tasks = new BehaviorSubject([]);

  constructor(private plt: Platform, private sqlitePorter: SQLitePorter, private sqlite: SQLite, private http: HttpClient) {
    this.plt.ready().then(() => {
      this.sqlite.create({
        name: 'mydatabase.db',
        location: 'default'
      })
      .then((db: SQLiteObject) => {
          this.database = db;
          this.seedDatabase();
      });
    });
  }

  seedDatabase() {
    this.http.get('assets/seed.sql', { responseType: 'text'})
    .subscribe(sql => {
      this.sqlitePorter.importSqlToDb(this.database, sql)
        .then(_ => {
          this.loadCategories();
          this.loadTasks();
          this.dbReady.next(true);
        })
        .catch(e => console.error(e));
    });
  }
 
  getDatabaseState() {
    return this.dbReady.asObservable();
  }
 
  getCats(): Observable<Cat[]> {
    return this.categories.asObservable();
  }
 
  getTasks(): Observable<any[]> {
    return this.tasks.asObservable();
  }

  loadCategories() {
    return this.database.executeSql('SELECT * FROM category', []).then(data => {
      let categories: Cat[] = [];
 
      if (data.rows.length > 0) {
        for (var i = 0; i < data.rows.length; i++) {
          let descriptions = [];
          if (data.rows.item(i).descriptions != '') {
            descriptions = JSON.parse(data.rows.item(i).descriptions);
          }
 
          categories.push({ 
            id: data.rows.item(i).id,
            name: data.rows.item(i).name, 
            descriptions: descriptions, 
            img: data.rows.item(i).img
           });
        }
      }
      this.categories.next(categories);
    });
  }

  addCategory(name, descriptions, img) {
    let data = [name, JSON.stringify(descriptions), img];
    return this.database.executeSql('INSERT INTO category (name, descriptions, img) VALUES (?, ?, ?)', data).then(data => {
      this.loadCategories();
    });
  }

  getCategory(id): Promise<Cat> {
    return this.database.executeSql('SELECT * FROM category WHERE id = ?', [id]).then(data => {
      let descriptions = [];
      if (data.rows.item(0).descriptions != '') {
        descriptions = JSON.parse(data.rows.item(0).descriptions);
      }
 
      return {
        id: data.rows.item(0).id,
        name: data.rows.item(0).name, 
        descriptions: descriptions, 
        img: data.rows.item(0).img
      }
    });
  }

  deleteCategory(id) {
    return this.database.executeSql('DELETE FROM category WHERE id = ?', [id]).then(_ => {
      this.loadCategories();
      this.loadTasks();
    });
  }

  updateCategory(cat: Cat) {
    let data = [cat.name, JSON.stringify(cat.descriptions), cat.img];
    return this.database.executeSql(`UPDATE category SET name = ?, descriptions = ?, img = ? WHERE id = ${cat.id}`, data).then(data => {
      this.loadCategories();
    })
  }

  loadTasks() {
    let query = 'SELECT task.name, task.description, task.id, task.name AS category FROM task JOIN category ON category.id = task.categoryId';
    return this.database.executeSql(query, []).then(data => {
      let tasks = [];
      if (data.rows.length > 0) {
        for (var i = 0; i < data.rows.length; i++) {
          tasks.push({ 
            description: data.rows.item(i).description,
            name: data.rows.item(i).name,
            id: data.rows.item(i).id,
            category: data.rows.item(i).category,
           });
        }
      }
      this.tasks.next(tasks);
    });
  }
 
  addTask(name, description, category) {
    let data = [name, description, category];
    return this.database.executeSql('INSERT INTO task (name, description, categoryId) VALUES (?, ?, ?)', data).then(data => {
      this.loadTasks();
    });
  }
}

categories.page.ts :

import { DatabaseService, Cat } from './../../services/database.service';
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
 
@Component({
  selector: 'app-categories',
  templateUrl: './categories.page.html',
  styleUrls: ['./categories.page.scss'],
})
export class CategoriesPage implements OnInit {
 
  categories: Cat[] = [];
 
  tasks: Observable<any[]>;
 
  category = {};
  task = {};
 
  selectedView = 'cats';
 
  constructor(private db: DatabaseService) { }
 
  ngOnInit() {
    this.db.getDatabaseState().subscribe(rdy => {
      if (rdy) {
        console.log('READY DB');
        this.db.getCats().subscribe(cats => {
          this.categories = cats;
        })
        this.tasks = this.db.getTasks();
      }
    });
  }
 
  addCategory() {
    let descriptions = this.category['descriptions'].split(',');
    descriptions = descriptions.map(description => description.trim());
 
    this.db.addCategory(this.category['name'], descriptions, this.category['img'])
    .then(_ => {
      this.category = {};
    });
  }
 
  addTask() {
    this.db.addTask(this.task['name'], this.task['description'], this.task['category'])
    .then(_ => {
      this.task = {};
    });
  }
 
}

and my html :

<ion-header>
  <ion-toolbar color="primary">
    <ion-title>Catégories</ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content padding>
 
  <ion-segment [(ngModel)]="selectedView">
    <ion-segment-button value="cats">
      <ion-label>Catégories</ion-label>
    </ion-segment-button>
    <ion-segment-button value="tasks">
      <ion-label>Tâches</ion-label>
    </ion-segment-button>
  </ion-segment>
 
  <div [ngSwitch]="selectedView">
    <div *ngSwitchCase="'cats'">
      <ion-item>
        <ion-label position="stacked">Nom de la catégorie</ion-label>
        <ion-input [(ngModel)]="category.name" placeholder="Nom de la catégorie"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label position="stacked">Descripteur (séparés par des virgules)</ion-label>
        <ion-input [(ngModel)]="category.descriptions" placeholder="Descripteurs"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label position="stacked">URL image</ion-label>
        <ion-input [(ngModel)]="category.img" placeholder="https://..."></ion-input>
      </ion-item>
      <ion-button expand="block" (click)="addCategory()">Ajouter Infos Catégorie</ion-button>
 
      <ion-list>
        <ion-item button *ngFor="let cat of categories" [routerLink]="['/', 'categories', cat.id]">
          <ion-avatar slot="start">
            <img [src]="cat.img">
          </ion-avatar>
          <ion-label>
            <h2>{{ cat.name }}</h2>
            <p>{{ cat.descriptions }}</p>
          </ion-label>
        </ion-item>
      </ion-list>
    </div>
 
    <div *ngSwitchCase="'tasks'">
      <ion-item>
        <ion-label position="stacked">Votre Tâche</ion-label>
        <ion-input [(ngModel)]="task.name" placeholder="Votre tâche"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label position="stacked">Description</ion-label>
        <ion-input [(ngModel)]="task.description" placeholder="Description"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label position="stacked">Catégorie</ion-label>
        <ion-select [(ngModel)]="task.category">
          <ion-select-option *ngFor="let cat of categories" [value]="cat.id">{{ cat.name }}</ion-select-option>
        </ion-select>
      </ion-item>
      <ion-button expand="block" (click)="addTask()">Ajouter Tâche</ion-button>
 
      <ion-list>
        <ion-item *ngFor="let task of tasks | async">
          <ion-label>
            <h2>{{ task.name }}</h2>
            <p>Catégorie : {{ task.category }}</p>
          </ion-label>
        </ion-item>
      </ion-list>
    </div>
  </div>
 
</ion-content>

Hello there,

I have been little busy so sorry for late reply.

I checked your code and the first problem I see is your insert query.

  1. the table name is “category” and not “categorie”.
  2. if the column is auto increment you can insert values to the column.

Try correcting it and let me know.