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

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); }
);

Related

Ionic + Firebase - Push notifications

I have a ionic + firebase chat app and I'd like to send a notification to a user when a new message is received.
In the Ionic oficial documentation, the recommended plugin for this is:
https://github.com/katzer/cordova-plugin-local-notifications
But as you can see inside the repository, it hasnt been updated since last february and based in comments inside it, it seems like it doesnt work with last Android OS versions.
Does anyone know an alternative?
Thanks!
I had the same problem to implement push notifications in my app last month. This is the best tutorial to do that: https://medium.com/#senning/push-notifications-with-ionic-and-cordova-plugin-firebase-ab0c0cad3cc0
I customized this tutorial to a file: messaging.service.ts
import {Injectable} from '#angular/core';
import {ApiService} from './api.service';
import {AppApiResponse} from '../interfaces/interfaces'
import {Firebase} from "#ionic-native/firebase";
import {Platform} from "ionic-angular";
import {AngularFirestore} from "#angular/fire/firestore";
#Injectable()
export class MessagingService {
private userUid: string;
constructor(private firebase: Firebase,
public afs: AngularFirestore,
public platform: Platform) {
}
initializeFirebase(userUid) {
this.userUid = userUid;
if (!this.platform.is("core")) {
this.firebase.subscribe("all");
this.platform.is('android') ? this.initializeFirebaseAndroid() : this.initializeFirebaseIOS();
}
}
initializeFirebaseAndroid() {
this.firebase.getToken().then(token => {
this.saveTokenToFirestore(token);
console.log('token android= ' + JSON.stringify(token));
});
this.firebase.onTokenRefresh().subscribe(token => {
this.saveTokenToFirestore(token);
console.log('token refresh android= ' + JSON.stringify(token));
});
this.subscribeToPushNotifications();
}
initializeFirebaseIOS() {
this.firebase.grantPermission()
.then(() => {
this.firebase.getToken().then(token => {
this.saveTokenToFirestore(token);
console.log('token ios= ' + JSON.stringify(token));
});
this.firebase.onTokenRefresh().subscribe(token => {
this.saveTokenToFirestore(token);
console.log('token refresh ios= ' + JSON.stringify(token));
});
this.subscribeToPushNotifications();
})
.catch((error) => {
this.firebase.logError('push erro ios= ' + error);
});
}
subscribeToPushNotifications() {
this.firebase.onNotificationOpen().subscribe((response) => {
console.log('response push= ' + JSON.stringify(response));
if (response.tap) {
//Received while app in background (this should be the callback when a system notification is tapped)
//This is empty for our app since we just needed the notification to open the app
} else {
//received while app in foreground (show a toast)
}
});
}
private saveTokenToFirestore(token) {
if (!token) return;
const devicesRef = this.afs.collection('devices');
const docData = {
token,
userId: this.userUid,
};
return devicesRef.doc(token).set(docData)
}
}
To use in your code is just include to page constructor:
public msgService: MessagingService
And use:
try {
this.msgService.initializeFirebase(user.uid);
} catch (error) {
console.log('fire push erro= ' + error);
}

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.

Ionic2 load rows from sqlite after database ready

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.

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.

How to use Sqlite with ionic 2 rc.0?

I would like to know how to use Sqlite with Ionic 2 rc.o release.I am finding it difficult as there are no examples for the latest version release and i am stuck.Nothing on the net seems to be updated.A supporting example for Sqlite would be of great use.
Thank you in advance.
1) First of all, navigate to the root folder of your project and add the plugin:
$ ionic plugin add cordova-sqlite-storage
$ npm install --save #ionic-native/sqlite
2) Create a new provider inside the project (in this example, called SqlStorage):
$ ionic g provider sqlStorage
3) I'd like to add an import to app.component.ts to initialize the plugin at startup, not mandatory:
import {SqlStorage} from '../providers/sql-storage';
...
...
constructor(public sqlStorage: SqlStorage){}
4) Add entry to app.module.ts, mandatory:
import { SQLite } from '#ionic-native/sqlite';
import { SqlStorage } from '../providers/sql-storage';
...
...
providers: [SQLite, SqlStorage]
5) Define the sql-storage.ts provider:
import { Injectable } from '#angular/core';
import { Platform } from 'ionic-angular';
import { SQLite, SQLiteObject } from '#ionic-native/sqlite';
#Injectable()
export class SqlStorage {
storage: any;
DB_NAME: string = '__ionicstorage';
constructor(public platform: Platform, public sqlite: SQLite) {
this.platform.ready().then(() => {
this.sqlite.create({ name: this.DB_NAME, location: 'default' })
.then((db: SQLiteObject) => {
this.storage = db;
this.tryInit();
});
});
}
tryInit() {
this.query('CREATE TABLE IF NOT EXISTS kv (key text primary key, value text)')
.catch(err => {
console.error('Unable to create initial storage tables', err.tx, err.err);
});
}
/**
* Perform an arbitrary SQL operation on the database. Use this method
* to have full control over the underlying database through SQL operations
* like SELECT, INSERT, and UPDATE.
*
* #param {string} query the query to run
* #param {array} params the additional params to use for query placeholders
* #return {Promise} that resolves or rejects with an object of the form
* { tx: Transaction, res: Result (or err)}
*/
query(query: string, params: any[] = []): Promise<any> {
return new Promise((resolve, reject) => {
try {
this.storage.transaction((tx: any) => {
tx.executeSql(query, params,
(tx: any, res: any) => resolve({ tx: tx, res: res }),
(tx: any, err: any) => reject({ tx: tx, err: err }));
},
(err: any) => reject({ err: err }));
} catch (err) {
reject({ err: err });
}
});
}
/** GET the value in the database identified by the given key. */
get(key: string): Promise<any> {
return this.query('select key, value from kv where key = ? limit 1', [key])
.then(data => {
if (data.res.rows.length > 0) {
return data.res.rows.item(0).value;
}
});
}
/** SET the value in the database for the given key. */
set(key: string, value: string): Promise<any> {
return this.query('insert into kv(key, value) values (?, ?)', [key, value]);
}
/** REMOVE the value in the database for the given key. */
remove(key: string): Promise<any> {
return this.query('delete from kv where key = ?', [key]);
}
}
6) In your .ts page:
import {SqlStorage} from '../../providers/sql-storage';
export class ExamplePage {
constructor(public sqlStorage: SqlStorage) {
// this.sqlStorage.query(...);
// this.sqlStorage.get(key).then(data => {
// console.log(data);
// }
//...
}
}
Credit to: https://github.com/NickStemerdink with some personal changes.
Hope it will help and works fine :)
EDIT: Still works fine with Ionic v3.0.1 (2017-04-06)
in app.module.ts
import { SQLite } from '#ionic-native/sqlite';
providers: [
StatusBar,
SplashScreen,
SQLite,
{ provide: ErrorHandler, useClass: IonicErrorHandler }
]
in database provider
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
//import { Storage } from '#ionic/storage';
import { SQLite, SQLiteObject } from '#ionic-native/sqlite';
import { Platform } from 'ionic-angular';
/*
Generated class for the Database provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class Database {
DB_NAME: string = 'ssddb';
constructor(public http: Http, public platform: Platform, public sqlite: SQLite) {
this.platform.ready().then(() => {
this.configureDatabase();
});
}
configureDatabase() {
this.query('CREATE TABLE IF NOT EXISTS EMP (key text primary key, value text)')
.catch(err => {
console.error('Unable to create initial storage tables', err.tx, err.err);
});
}
query(query: string, params: any[] = []): Promise<any> {
return new Promise((resolve, reject) => {
try {
this.sqlite.create({
name: this.DB_NAME,
location: 'default'
})
.then((db: SQLiteObject) => {
db.transaction((tx: any) => {
tx.executeSql(query, params,
(tx: any, res: any) => resolve({ tx: tx, res: res }),
(tx: any, err: any) => reject({ tx: tx, err: err }));
})
})
.catch(e => console.log(e));
} catch (err) {
reject({ err: err });
}
});
}
get(key: string): Promise<any> {
return this.query('select key, value from EMP where key = ? limit 1', [key])
.then(data => {
if (data.res.rows.length > 0) {
return data.res.rows.item(0).value;
}
});
}
set(key: string, value: string): Promise<any> {
return this.query('insert into EMP(key, value) values (?, ?)', [key, value]);
}
}
in page.ts
this.database.set("333","ss");
this.database.get("333").then(data => {
console.log(data);
let toast = this.toastCtrl.create({
message: data,
duration: 10000,
position: 'bottom'
});
toast.present();
});
On ionic-storage repo they say to use Ionic Native SQLite plugin.
So like this:
import { SQLite } from 'ionic-native';
SQLite.openDatabase({
name: 'data.db',
location: 'default'
})
.then((db: SQLite) => {
db.executeSql('create table danceMoves(name VARCHAR(32))', {}).then(() => {}).catch(() => {});
})
.catch(error => console.error('Error opening database', error));

Resources