Ionic2 load rows from sqlite after database ready - sqlite

I have an ionic 2 app with a database service powered by sqlite. The database stores a couple rows of items. The first page of the app displays those items. The issue I'm running into is that the page attempts to load the items before the service has loaded the database. I get this error:
Cannot read property 'executeSql' of undefined
If i navigate to a different page and back to home, it loads correctly. This is the database service. I'm attempting to call getScanables on the first page.
import { Injectable } from '#angular/core';
import {SQLite} from 'ionic-native';
import {Platform} from 'ionic-angular';
#Injectable()
export class Database {
private storage: SQLite;
public isOpen: boolean;
public constructor(private platform: Platform,) {
console.log('Creating storage.');
platform.ready().then(() => {
console.log('Platform Ready.');
if(!this.isOpen) {
console.log('Database Unopened');
this.storage = new SQLite();
this.storage.openDatabase({name: "data.db", location: "default"}).then(() => {
console.log('Generating Database');
this.storage.executeSql("CREATE TABLE IF NOT EXISTS scanables (id INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT, type TEXT, name TEXT, date TEXT)", []);
//this.storage.executeSql("CREATE TABLE IF NOT EXISTS journal (id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT, descriptors TEXT, image TEXT, behaviors TEXT)", []);
console.log('Generated.');
this.isOpen = true;
}, (error) => {
console.log("Error opening database.", error);
});
}
});
}
public getScanables() {
console.log('Getting Scanables');
return new Promise((resolve, reject) => {
this.storage.executeSql("SELECT * FROM scanables", []).then((data) => {
let journal = [];
if(data.rows.length > 0) {
for(let i = 0; i < data.rows.length; i++) {
journal.push({
id: data.rows.item(i).id,
value: data.rows.item(i).value,
type: data.rows.item(i).type,
name: data.rows.item(i).name,
date: data.rows.item(i).date,
letter_one: data.rows.item(i).name.substring(0,1)
});
}
}
resolve(journal);
}, (error) => {
reject(error);
});
});
}
...
}
This is the relevant code for the first page:
#Component({
templateUrl: 'journal.html'
})
export class JournalPage implements AfterViewInit {
public orderType: string = 'delivery';
public autocomplete: {term: string, place: any};
public regions: any;
public itemList: Array<Object>;
public addList: Array<number>;
constructor(private navCtrl: NavController,
private menu: MenuController,
private modalCtrl: ModalController,
private database: Database,
public userService: UserService,
private helper: Helper,
private l: LoggerService) {
this.itemList = [];
this.addList = [1,2,3,4,5,6,7];
}
ngAfterViewInit(): any {
console.log('journal.ngAfterViewInit');
this.load();
}
public load() {
console.log('journal.load');
this.database.getScanables().then((result) => {
console.log('entered getScanables');
this.itemList = <Array<Object>> result;
console.log('itemList', this.itemList);
}, (error) => {
this.l.error('journal.ts:', error);
});
}
...

The solution for this issue was to make the service's database a public variable and load the database on load. Then only after loading the database we set the root page. This forces the database to load first. May not be the ideal solution though, so feel free to post additional answers.

Related

ionic executeSql doesn't work

I actually try to make an mobile app with SQLite. I juste try to create two tables:
constructor(private sqlite:SQLite,public modalCtrl: ModalController,public navCtrl: NavController, private navParam: NavParams, private databaseprovider: DatabaseProvider, private employeesProvider: EmployeeProvider) {
this.createDetabaseFile();
}
private createDetabaseFile() : void {
this.sqlite.create({
name: DATABASE_FILE_NAME,
location: 'default'
}).then((dbRes: SQLiteObject) => {
alert("bdd créée");
this.db = dbRes;
this.createTables();
})
}
private createTables() : void {
this.db.executeSql('CREATE table IF NOT EXISTS symbole(id INTEGER NOT NULL ,name TEXT)',{})
.then(() => {
alert("table symbole created");
this.db.executeSql('CREATE table IF NOT EXISTS representationPhoto(name VARCHAR(32))',{})
.then(() => {
alert("table representationPhoto created");
})
.catch(e => alert("erreur creation table"));
})
.catch(e => alert("erreur creation table"));
}
And db.executeSql() seem not working, indeed, the alert("table symbole created"); don't appear, however alert("bdd créée") appear, and the program don't triggered the catch.
Have you an idea?
ps: sorry for my bad english
Kindly try declaring db variable above createDetabaseFile function it seems to me the problem because you are using this.db without declaring it in the class scope.
Try doing this:
public db: any; // above createDetabaseFile function
You're missing platform ready block before handling SQLite.Try this:
import { Platform } from 'ionic-angular';
constructor(private platform: Platform, ...other imports) {
this.platform.ready().then(() => {
this.createDetabaseFile();
})
}

SQLite in Ionic 3 getting data null after navigate to another page

Please help me. I've made Database Provider to connect with SQLite in ionic 3. When i want to get the data rows it's always getting null but when I check data length it has 1
This is my DatabaseProvider
import { Injectable } from '#angular/core';
import { Platform } from 'ionic-angular';
import { SQLite, SQLiteObject } from '#ionic-native/sqlite';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Storage } from '#ionic/storage';
#Injectable()
export class DatabaseProvider {
private db: SQLiteObject;
private databaseReady: BehaviorSubject<boolean>;
constructor(private storage: Storage, private sqlite: SQLite, private platform: Platform) {
this.databaseReady = new BehaviorSubject(false);
this.platform.ready().then(() => {
this.sqlite.create({
name: 'takia.db',
location: 'default'
}).then((database: SQLiteObject) => {
this.db = database;
this.storage.get('database_filled').then(val => {
if (val) {
this.databaseReady.next(true);
} else {
this.initDB();
}
});
}).catch(e => { console.log(e); });
});
}
initDB(){
this.db.executeSql('CREATE TABLE IF NOT EXISTS users(user_id INTEGER PRIMARY KEY, username TEXT, email TEXT, password TEXT)', {})
.then(res => {
this.db.executeSql('INSERT INTO users VALUES(NULL,?,?,?,?)',['admin','admin.#email.com','password'])
.then(res => {
this.databaseReady.next(true);
this.storage.set('database_filled', true);
}).catch(e => {
console.log(e);
});
}).catch(e => {
console.log(e)
});
this.db.executeSql('CREATE TABLE IF NOT EXISTS questions(user_id INTEGER PRIMARY KEY, username TEXT, email TEXT, password TEXT)', {})
.then(res => {
this.db.executeSql('INSERT INTO users VALUES(NULL,?,?,?,?)',['admin','admin.tazkiaiibs.sch.id','bismillah'])
.then(res => {
this.databaseReady.next(true);
this.storage.set('database_filled', true);
}).catch(e => {
console.log(e);
});
}).catch(e => {
console.log(e)
});
}
getUser(){
return this.db.executeSql('SELECT user_id, username, email, password, COUNT(*) total FROM users', [])
.then(res => {
let users = [];
if (res.rows.length > 0) {
for (var i = 0; i < res.rows.length; i++) {
let row = res.rows.item(i);
users.push(row);
}
}
return users;
}, err => {
console.log('Error: ', err);
return [];
});
}
getDatabaseState() {
return this.databaseReady.asObservable();
}
}
and this is my code in component
constructor(public navCtrl: NavController,
public navParams: NavParams,
private dbProvider: DatabaseProvider,
private toastCtrl: ToastController) {
this.loadData();
}
loadData(){
this.dbProvider.getUser().then(data=>{
if(data.length>0){
this.id = data[0].id;
this.old_password = data[0].password;
this.username = data[0].username;
this.email = data[0].email;
let toast = this.toastCtrl.create({
message: 'ID '+data[0].username,
duration: 3000
});
toast.present();
}else{
let toast = this.toastCtrl.create({
message: 'No data'+data.length,
duration: 3000
});
toast.present();
}
});
}
When i run loadData function the length is not 0 but the data is null.
The comment under the question seemed to help, so I form it as an answer to hopefully collect some reputation points.
The problem seems to be a misformed SQL-query. The count(*) part makes the query return at least one row. Therefore the other fields might be NULL, when queried before data is added to the database.
The function "getUser" is called before the promise callback is executed.

Using an existing database in Ionic - Visual Studio 2017 mobile app

I have created a database using DB Browser For SQLite called data.db with the file is saved in the directory www/
Here is my home.ts file:
import { Component } from '#angular/core';
import { Platform, NavController, NavParams, ViewController, PopoverController } from 'ionic-angular';
import { SQLite } from "ionic-native";
import { RatesPage } from '../rates/rates';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public itemList: Array<Object>;
public database: SQLite;
constructor(public popoverCtrl: PopoverController, public navCtrl: NavController, public platform: Platform) {
this.itemList = [];
this.platform.ready().then(() => {
this.database = new SQLite();
this.database.openDatabase({
name: "data.db",
location: "default"
}).then((data) => {
this.database.executeSql("CREATE TABLE IF NOT EXISTS people (id INTEGER PRIMARY KEY AUTOINCREMENT, firstname TEXT, lastname TEXT)", {})
.then((data) => {
console.log("TABLE CREATED: ", data);
alert('db and table created ');
}, (error) => {
alert("Unable to execute sql " + error);
})
}, (error) => {
alert("Unable to open database " + error);
});
});
}
}
I have used this link to help me.
I do not understand why I have to create a table while i'm including a full database?

Ionic 2: Unable to create table TypeError: Cannot read property 'apply' of undefined

I am trying to open a database and create a table in my Ionic 2 app.
The following method is part of a service and is supposed to open the db and create the table:
initDb() {
let db = new SQLite();
db.openDatabase({
name: "data.db",
location: "default"
}).then(() => {
db.executeSql("CREATE TABLE IF NOT EXISTS people (avatarUrl VARCHAR, firstName VARCHAR, lastName VARCHAR)", []).then((data) => {
console.log("Table created: ", data);
}, (error) => {
console.error("Unable to create table", error);
})
}, (error) => {
console.error("Unable to open database", error);
});
}
The method is called in my home page's constructor:
constructor(public platform: Platform, public navCtrl: NavController, public dbService: DBService) {
this.platform.ready().then(() => {
this.dbService.initDb();
});
}
I have no idea why I am getting this error (refer to the title).
Thanks
Sorry, I could not reproduce this error but build a testapp on my own. This app works with me, despite this is called within ready as well:
app.component.ts:
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar, Splashscreen, SQLite } from 'ionic-native';
import { TabsPage } from '../pages/tabs/tabs';
import { DbService } from '../providers/db-service';
#Component({
templateUrl: 'app.html',
providers: [DbService]
})
export class MyApp {
rootPage = TabsPage;
constructor(public platform: Platform, public dbService: DbService) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
Splashscreen.hide();
this.dbService.initDb();
});
}
}
I made this service by using this ionic-command:
ionic g provider DbService
db-service.ts:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import { SQLite } from 'ionic-native';
/*
Generated class for the DbService provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class DbService {
constructor(public http: Http) {
console.log('Hello DbService Provider');
}
initDb() {
let db = new SQLite();
db.openDatabase({
name: "data.db",
location: "default"
}).then(() => {
db.executeSql("CREATE TABLE IF NOT EXISTS people (avatarUrl VARCHAR, firstName VARCHAR, lastName VARCHAR)", []).then((data) => {
console.log("Table created: ", data);
}, (error) => {
console.error("Unable to create table", error);
})
}, (error) => {
console.error("Unable to open database", error);
});
}
}
ionic-version: 2.1.18
cordova-version 6.0.0
Hope it helps.

ionic 2 sqlite run on android : cannot read property executeSql of undefined

I write a test tabs ionic 2 app use sqlite plugin. I wrapper the sqlite as provier:
import { SQLite, Device } from 'ionic-native';
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
/*
Generated class for the SqliteHelper provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class SqliteHelper {
public db : SQLite;
public log : string = "";
constructor(public http: Http) {
console.log('Hello SqliteHelper Provider');
}
public initDb() {
this.db = new SQLite();
this.log += "openDatabase。。。";
// if (Device.device.platform)
this.db.openDatabase({
name: "data.db",
location: "default"
}).then((data) =>{
this.log += ("open ok " + JSON.stringify(data));
}, (err) => {
this.log += ("open err " + err.message + " " + JSON.stringify(err));
});
}
public executeSql(statement: string, parms:any) {
return this.db.executeSql(statement, parms);
}
}
And init sqlitehelper in app.components :
constructor(platform: Platform, sqliteHelper : SqliteHelper, events: Events) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
sqliteHelper.initDb();
events.publish("sqlite:inited", null);
StatusBar.styleDefault();
Splashscreen.hide();
});
}
And I load data from the first tabs page in constructor with platform.ready, run it on android will cause err: cannot read property executeSql of undefined.
If I load data from a button click, it's ok. or I put the loaddata to the second page's constructor, it's ok too.why?who can help me , I want to put code to the first page and load data at page started.
I had the same error when i try to insert in database for that reason i added "executeSql" function inside transaction:
this.database.openDatabase({
name: "sis.db",
location: "default"
}).then(() => {
this.database.executeSql("CREATE TABLE IF NOT EXISTS profile(id integer primary key autoincrement NOT NULL ,name Text NOT NULL)", []).then((data) => { console.log('profile table created'); }, (error) => { console.log('Unable to create table profile'); })
this.database.transaction(tr => { tr.executeSql("insert into profile(id,name) values(12,'Ibrahim')", []); }).then(d => { console.log('Data inserted ya hima'); }, err => { console.error('unable to insert data into profile table'); });
this.database.executeSql("select id from profile", []).then(d => { console.log('inserted id=' + d.rows.item(0).app_id); }, err => { console.error('unable to get ID from profile table'); });
}, (error) => {console.error(error); }
);

Resources