I'm been using the ionic 2 native sqlite plugin to make a basic app to capture and store images to the phones local storage. I keep getting an uncaught exception error (seemingly from the sql plugin) sometimes when i run the app on the genymotion emulator.
This normally happens when the app reloads when i'm using the -live parameter(ionic run android -c -l).
I also noticed that data which stored on the app doesn't appear(this again indicates that there is some problem loading the stored data when 'live reloading')
I've put the error i get on the console below:
The Console error message
[13:28:27] Starting 'html'...
[13:28:27] Finished 'html' after 42 ms
HTML changed: www/build/pages/home/home.html
HTML changed: www/build/pages/map-detail-component/map-detail-component.html
HTML changed: www/build/pages/map-page/map-page.html
0 298305 log Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.
1 298474 group EXCEPTION: Error: Uncaught (in promise): ReferenceError: sqlitePlugin is not defined
2 298475 error EXCEPTION: Error: Uncaught (in promise): ReferenceError: sqlitePlugin is not defined
3 298476 error STACKTRACE:
4 298477 error Error: Uncaught (in promise): ReferenceError: sqlitePlugin is not defined
at resolvePromise (http://192.168.56.1:8100/build/js/zone.js:418:31)
at resolvePromise (http://192.168.56.1:8100/build/js/zone.js:403:17)
at http://192.168.56.1:8100/build/js/zone.js:451:17
at ZoneDelegate.invokeTask (http://192.168.56.1:8100/build/js/zone.js:225:37)
at Object.NgZoneImpl.inner.inner.fork.onInvokeTask (http://192.168.56.1:8100/build/js/app.bundle.js:37360:41)
at ZoneDelegate.invokeTask (http://192.168.56.1:8100/build/js/zone.js:224:42)
at Zone.runTask (http://192.168.56.1:8100/build/js/zone.js:125:47)
at drainMicroTaskQueue (http://192.168.56.1:8100/build/js/zone.js:357:35)
at XMLHttpRequest.ZoneTask.invoke (http://192.168.56.1:8100/build/js/zone.js:297:25)
5 298478 groupEnd
6 298481 error Unhandled Promise rejection:, sqlitePlugin is not defined, ; Zone:, angular, ; Task:, Promise.then, ; Value:, [object Object], ReferenceError: sqlitePlugin is not defined
at http://192.168.56.1:8100/build/js/app.bundle.js:97420:13
at new ZoneAwarePromise (http://192.168.56.1:8100/build/js/zone.js:467:29)
at SQLite.openDatabase (http://192.168.56.1:8100/build/js/app.bundle.js:97419:16)
at new SqlService (http://192.168.56.1:8100/build/js/app.bundle.js:218:21)
at DebugAppView.Object.defineProperty.get (MyApp.template.js:18:67)
at DebugAppView._View_MyApp_Host0.injectorGetInternal (MyApp.template.js:35:79)
at DebugAppView.AppView.injectorGet (http://192.168.56.1:8100/build/js/app.bundle.js:31753:21)
at DebugAppView.injectorGet (http://192.168.56.1:8100/build/js/app.bundle.js:31945:49)
at ElementInjector.get (http://192.168.56.1:8100/build/js/app.bundle.js:31246:33)
at ElementInjector.get (http://192.168.56.1:8100/build/js/app.bundle.js:31249:48)
7 298519 log DEVICE READY FIRED AFTER, 1004, ms
8 298609 log Entering: map-page
9 298620 log ERROR: , {}
This goes away when i restart the emulator but then sometimes appears again after more usage.
I thought this could be due to the SQLite db being created before the plugin is imported but i've imported the plugin in my root app.ts file (shown below) (the whole app can be seen in this github repo)
Root app.ts
#Component({
template: '<ion-nav [root]="rootPage"></ion-nav>',
// Declare services
providers: [ SqlService ]
})
export class MyApp {
rootPage: any = MapPage;
constructor(platform: Platform) {
platform.ready().then(() => {
StatusBar.styleDefault();
});
}
}
ionicBootstrap(MyApp);
I've confined any use of the plugin to an sqlService (shown below)
SQL Service
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/map';
import { SQLite} from 'ionic-native';
#Injectable()
export class SqlService {
private db: SQLite;
private isOpen: boolean;
public constructor() {
if(!this.isOpen){
this.db = new SQLite();
this.db.openDatabase({
name: "data.db",
location: "default"
}).then(() => {
this.db.executeSql("CREATE TABLE IF NOT EXISTS places (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, img TEXT)", []).then((data) => {
console.log("TABLE CREATED: " + data);
}, (error) => {
console.log("Unable to execute SQL" + error);
});
this.isOpen=true;
});
}
}
public add(title: string, base64Img: string) {
return new Promise((resolve, reject) => {
this.db.executeSql("INSERT INTO places (title, img) VALUES ( '"+ title +"', '"+ base64Img +"')", [])
.then((data) => {
resolve(data);
}, (error) => {
reject(error);
});
});
}
// Remove individual Location
public remove(id: number){
return new Promise((resolve, reject) => {
this.db.executeSql("DELETE FROM places WHERE id = "+ id +";", [])
.then((data) => {
resolve(data);
}, (error) => {
reject(error);
});
});
}
public locDetail(id: number){
return new Promise((resolve, reject) => {
this.db.executeSql("SELECT * FROM places WHERE id = "+ id +";",[])
.then((data) => {
if(data.rows.length===1){
// console.log("ttitle: " + data.rows.item(0).title + " id: " + data.rows.item(0).id + " img: " + data.rows.item(0).img );
let place = [];
place.push({
id: data.rows.item(0).id,
title: data.rows.item(0).title,
img: data.rows.item(0).img
});
resolve(place);
}
}, (error) => {
reject(error);
});
});
}
// Refresh and initialise the places object
public refresh() {
return new Promise((resolve, reject) => {
this.db.executeSql("SELECT * FROM places", []).then((data) => {
let place = [];
if (data.rows.length > 0) {
for (var i = 0; i < data.rows.length; i++) {
place.push({
id: data.rows.item(i).id,
title: data.rows.item(i).title,
img: data.rows.item(i).img
});
}
}
resolve(place);
}, (error) => {
reject(error);
});
}
);
}
}
I recently had the same problem, make sure you check if the platform is ready also in your service. Import "Platform" from "ionic-angular" and execute your sqlite interaction code in the promise.then method.
I am using IOS and get the same error 'ReferenceError: sqlitePlugin is not defined'.
As the sqlite does not work when testing in Chrome browser I tried the ionic upload CLI function. Then got the same error.
I came across this issue on Github.
After using setTimeout it works in the Ionic view app on IOS:
setTimeout(function() {
let db = new SQLite();
db.openDatabase({
name: "data.db",
location: "default"
}).then(() => {
db.executeSql("CREATE TABLE IF NOT EXISTS people (id INTEGER PRIMARY KEY AUTOINCREMENT, firstname TEXT, lastname TEXT)", {}).then((data) => {
console.log("TABLE CREATED: ", data);
self.dummy = data
}, (error) => {
console.error("Unable to execute sql", error);
self.dummy = error;
})
}, (error) => {
console.error("Unable to open database", error);
self.dummy = error;
});
}, 2000);
please run your projeect in emulator/simulator or android device/ios device.it's not work on browser.
Related
This is the code is in my /app/lib/litProtocolFunctions.ts file which is where I reference LitJsSdk:
//#ts-ignore
import LitJsSdk from 'lit-js-sdk';
import { baseUrlConf } from '#/lib/config';
export function disconnectLit() {
LitJsSdk.disconnectWeb3();
return 'lit-auth';
}
export async function connectLit(uuidSpec: string) {
const resourceId = {
baseUrl: "http://" + baseUrlConf + ":3000",
path: '/protected',
orgId: "",
role: "",
extraData: uuidSpec
}
const chain = 'mumbai'
const accessControlConditions = [
{
contractAddress: '<MY CONTRACT'S ADDRESS>',
standardContractType: 'ERC721',
chain: chain,
method: 'balanceOf',
parameters: [
':userAddress'
],
returnValueTest: {
comparator: '>',
value: '0'
}
},
]
const client = new LitJsSdk.LitNodeClient({ alertWhenUnauthorized: false });
//#ts-ignore
await client.connect();
const authSig = await LitJsSdk.checkAndSignAuthMessage({ chain });
//#ts-ignore
await client.saveSigningCondition({ accessControlConditions, chain, authSig, resourceId })
try {
//#ts-ignore
const litjwt = await client.getSignedToken({
accessControlConditions, chain, authSig, resourceId: resourceId
});
return litjwt;
} catch (err) {
console.log('error: ', err);
return 'no-token';
}
}
When I run the app in next.js 13 with webpack it works perfectly. When I run it in next.js 13 with turbopack it fails with a non-helpful error that looks like this:
Also, it says this in my terminal (the one I used to launch the app): Error during SSR Rendering TypeError: Class extends value #<Object> is not a constructor or null.
And it says this in the browser console Uncaught ReferenceError: $RefreshSig$ is not defined.
I believe I've traced the error to it's point of failure.
This is where the error starts:
And this is the line 1:332 in node_module/lit-js-sdk/build/index.js:
So is it an issue with h=require ("#walletconnect/ethereum-provider")?
I'm using ionic3 and am trying to unit test (using Jasmine/karma) the following code. Can anyone offer any guidance.
createTable(databaseName: string): Promise<any> {
let sql = 'CREATE TABLE IF NOT EXISTS table)';
return new Promise((resolve, reject) => {
this.sqlite.create({
name: databaseName + '.db',
location: 'default'
}).then((db: SQLiteObject) => {
db.executeSql(sql, [])
.then(() => {
console.info('Executed SQL');
})
.catch((e) => {
console.error('createTable Error', e.message);
reject(e);
});
});
})
}
Here's my work in progress attempt to test
describe('createTable()', () => {
let db: SQLiteObject;
it('Should call function createTable', () => {
spyOn(service.sqlite, 'create').and.returnValue(Promise.resolve(
));
let databaseName = 'testDatabase';
service.createEncounterTable(databaseName);
expect(service.sqlite.create).toHaveBeenCalled();
});
});
I'm getting the following error return ERROR: 'Unhandled Promise rejection:', 'Cannot read property 'executeSql' of undefined', and dont seem to be able to gain access to executeSql.
As far as I can tell, from the lack of online resource on testing SQLite I have to assume that most people don't test this. Thanks in advance to any guidance.
I'm subscribing to a service to get an Array of Teams
teamService code:
Here my teamService code (get results from firebase):
getTeams(): Observable<Team[]> {
this.login();
let teams: Team[] = [];
return this._db.list('teams')
.map((response) => {
response.forEach(team => {
this._fb.storage().ref().child('teams/' + team.photo).getDownloadURL()
.then(imageUrl => {
teams.push(new Team(team.id, team.name, imageUrl, team.zone, team.points, team.matchesPlayed,
team.matchesWon, team.matchesDrawn, team.matchesLost, team.goalsScored,
team.goalsReceived, team.dif));
})
.catch(error => {
console.log(error);
});
});
return teams;
});
}
Here I'm subscribing to my service to get the teams:
loadStandings() {
let loading = this.loadingCtrl.create({
spinner: 'crescent'
});
loading.present();
this.teamService.getTeams().subscribe(t => {
this.teams = t;
console.log('showing this.teams');
console.log(this.teams); // this.teams declared as any[]
this.teamsOrdered = _.orderBy(this.teams, ['points', 'dif'], ['desc', 'desc']);
console.log('showing this.teamsOrdered');
console.log(this.teamsOrdered); // this.teamsOrdered declared as any[]
});
loading.dismiss();
}
console.log(this.teams) shows me the expected array returned from the service but console.log(this.teamsOrdered) is empty.
Lodash is imported import * as _ from 'lodash'; at the top of my ts file
Here screenshot from console
Edit: I added my getTeamsService code, when debugging (put a breakpoint on console.log(this.teams); I realized that the code below this.teams=t is executing before the values are retrieved from the service call.
If I don't debug then the result are in the same from my console output screenshot.
What am I doing wrong?
I'm using Ionic 2 (Angular 2) for a Hybrid app. I inject a shared provider into the page that will display data from my SQLite3 database and then proceed to load the data. However, on creation of my database provider opening the database takes some time (very little). My code (as of this moment) however does not wait for the database to be opened before querying, which obviously results in an error.
How can I structure my code that it will wait for the database to be opened in order to evade a crash?
The constructor of my database provider:
constructor(private platform: Platform) {
this.platform.ready().then(() => {
if(this.isOpen !== true) {
this.storage = new SQLite();
this.storage.openDatabase({name: "data.db", location: "default"}).then(() => {
this.isOpen = true;
this.storage.executeSql("CREATE TABLE IF NOT EXISTS people (id INTEGER PRIMARY KEY AUTOINCREMENT, firstname TEXT, lastname TEXT)", []);
});
}
});
console.log('Hello Database Provider');
This provider gets injected into the constructor of my page.
When the page (home page) is loaded it triggers an event that calls a load() function.
ionViewDidLoad() {
this.load();
console.log('Hello Home Page');
The load function:
public load() {
this.database.getPeople().then((result) => {
this.itemList = <Array<Object>> result;
}, (error) => {
console.log("LOAD ERROR: ", error);
});
I'm very much hoping someone can point me in the right direction :)
I've finally found a solution to my problem.
For starters I've added a function to my provider that checks if the database is loaded, if it isn't it proceeds to load it:
public openSQLiteDatabase() {
return new Promise((resolve, reject) => {
if(this.isOpen) {
console.log("DB IS OPEN");
resolve(this.isOpen);
}
else {
console.log("DB IS NOT OPEN");
this.platform.ready().then(() => {
this.storage.openDatabase({name: "data.db", location: "default"}).then(() => {
this.appsettings.openSQLiteDatabase().then(() => {
this.appsettings.getSettings().then((result) => {
let settings: Settings = <Settings> result;
this.selectedDataset = settings.selectedDataset;
this.isOpen = true;
resolve(this.isOpen);
});
});
}, (error) => {
reject(error);
});
});
}
});}
As this function returns a promise (JS Promises) it allows me to wait for the database to be opened before doing anything else (such as querying).
My function in the page-specific TypeScript file:
ionViewDidLoad() {
this.database.openSQLiteDatabase().then(() => {
this.loadDictionary();
});}
With code like this I never have problems with queries being performed before my database has been opened!
I am trying to create a DB service. The initializeDb function is being called from app.ts. Snippet of provider/data/data.ts is like
import {Injectable} from 'angular2/core';
import {Platform, Storage, SqlStorage} from 'ionic-angular';
#Injectable()
export class Data {
dbHandle;
platform;
constructor(platform: Platform) {
this.platform = platform;
}
public initializeDataService() {
this.platform.ready().then(() => {
console.log('initializing db');
this.dbHandle = new Storage(SqlStorage);
this.dbHandle.query('CREATE TABLE IF NOT EXISTS APP_DATA (KEY_NAME TEXT PRIMARY KEY, KEY_VALUE TEXT)').
then((data) => { console.log('Table created succesfully' + JSON.stringify(data)); return; },
(error) => { console.log('Error while creating table: ' + JSON.stringify(error)); return; });
});
}
getRecord(key_name) {
let result = {};
console.log('trying to get record for ' + key_name);
this.dbHandle.query("SELECT * FROM APP_DATA WHERE KEY_NAME = '" + key_name + "'").
then((data) => {
console.log('Data obtained from db is ' + JSON.stringify(data));
if (data.res.rows.length > 0) {
return data.res.rows.item(0);
}
else {
return result;
}
},
(error) => {
console.log('Error while selecting record for ' + key_name + ' error is: ' + JSON.stringify(error));
return result;
});
console.log('This should have never been reached');
}
}
Another page, viz. login looks like:
import {Platform, Page, NavController} from 'ionic-angular';
import {Http, Headers} from 'angular2/http';
import {Data} from '../../providers/data/data';
#Page({
templateUrl: 'build/pages/login/login.html',
})
export class LoginPage {
platform;
constructor(platform: Platform, private data: Data, private http: Http) {
this.platform = platform;
this.platform.ready().
then(() => {
this.checkLogin();
});
}
checkLogin() {
this.platform.ready().
then(() => {
this.loginRec = this.data.getRecord('LOGIN_REC');
console.log('Login Rec from DB is '+JSON.stringify(this.loginRec));
if ({} == this.loginRec) {
// take to sign-up
console.log('No local login rec present');
}
else {
// try to do specific login
console.log('Somethign present');
}
},
(error) => {
console.log('LoginPage: Platform not yet ready');
});
};
}
Now here is the snapshot of the log:
1 414909 log Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.
2 415686 log LoginPage
3 416134 log Inside app.ts
4 416136 log initializing db
5 416144 log OPEN database: __ionicstorage
6 416156 log new transaction is waiting for open operation
7 416158 log new transaction is waiting for open operation
12 416175 log Login Rec from DB is undefined
8 416160 log Returning db handle
9 416166 log trying to get record for LOGIN_REC
10 416169 log new transaction is waiting for open operation
11 416173 log This should have never been reached
14 416195 log DB opened: __ionicstorage
13 416179 log Somethign present
15 416229 log Table created succesfully{"tx":{"db":{"openargs":{"name":"__ionicstorage","location":2,"createFromLocation":0,"backupFlag":2,"existingDatabase":false,"dblocation":"nosync"},"dbname":"__ionicstorage"},"txlock":true,"readOnly":false,"executes":[],"finalized":true},"res":{"rows":{"length":0},"rowsAffected":0}}
16 416250 log Data obtained from db is {"tx":{"db":{"openargs":{"name":"__ionicstorage","location":2,"createFromLocation":0,"backupFlag":2,"existingDatabase":false,"dblocation":"nosync"},"dbname":"__ionicstorage"},"txlock":true,"readOnly":false,"executes":[],"finalized":true},"res":{"rows":{"length":0},"rowsAffected":0}}
From the log it seems that opening of DB is being done in back-ground and execution proceeds.
All the DB operations seems to be queued till the time DB is opened
What i want is DB to be opened and only after it is successfully opened do all other operations. For this I always though promise/then helps. Logs suggests otherwise.
Any pointers/suggestion on how to achieve this appreciated
Thanks in advance
~Dhaval
You can use observable instead of promise with Angular 2.. You have to create an observable like this:
doSomeWork(){
return Observable.create(observer => {
//do some rest call or Database queries.
observer.next(someResult);
observer.complete();
});
}
and subscribe on it like this:
this.doSomeWork().subscribe(data=>{
// do something with the data
});
here is a code snippet that might work with your code (I have not checked formatting)
getRecord(key_name) {
let result = {};
console.log('trying to get record for ' + key_name);
return Observable.create(observer => {
this.dbHandle.query("SELECT * FROM APP_DATA WHERE KEY_NAME = '" + key_name + "'").then((data) => {
console.log('Data obtained from db is ' + JSON.stringify(data));
if (data.res.rows.length > 0) {
observer.next(data.res.rows.item(0));
}
else {
observer.next(result);
}
observer.complete();
},(error) => {
console.log('Error while selecting record for ' + key_name + ' error is: ' + JSON.stringify(error));
observer.next(result);
observer.complete();
});
console.log('This will never be reached');
});
}
and when you want to get the record, you have to subscribe on the observable you created.
this.getRecord('LOGIN_REC').subscribe(data => {
console.log("data",data);
});
It might not be an apt solution but the following did work for me.
1. I put Data as a provider in my app.ts
2. Made home page as an intermediate root page (instead of loginPage)
#App({
template: '<ion-nav [root]="rootPage"></ion-nav>',
providers: [Data],
config: {} // http://ionicframework.com/docs/v2/api/config/Config/
})
export class MyApp {
platform;
rootPage;
constructor(platform: Platform, private data : Data) {
console.log('app.ts constructor');
this.platform = platform;
this.initializeApp(data);
this.rootPage = HomePage;
}
initializeApp(data) {
this.platform.ready().then( () => {
console.log('Inside app.ts');
});
}
}
3. In HomePage only navigated to LoginPage on deviceRead
this.platform.ready().
then(() => {
console.log('HomePage: Platform ready');
this.nav.push(LoginPage);
});
4. Refactored the getRecord function in data.ts to return a promise
getRecord(key_name) {
let result = {};
return new Promise( (resolve, reject) => {
this.dbHandle.query("SELECT * FROM APP_DATA WHERE KEY_NAME = '" + key_name + "'")
.then((data) => {
console.log('Data obtained from db is ' + JSON.stringify(data));
if (data.res.rows.length > 0) {
console.log('Something is present');
resolve(data.res.rows.item(0));
}
else{
console.log('Sending back empty record');
resolve(result);
}
},
(error) => {
console.log('Error while selecting record for ' + key_name + ' error is: ' + JSON.stringify(error));
reject(error);
});
});
}
5. Finally checking the promise in login.ts as:
this.data.getRecord('LOGIN_REC').
then((data) => {
console.log('Login Rec from DB is ' + JSON.stringify(data));
this.loginRec = data;
if ({} == this.loginRec) {
// take to sign-up
console.log('No local login rec present');
} else {
// try to do specific login
console.log('Somethign present');
}
}, (error) => {
console.log('couldnt fetch record from db' + JSON.stringify(error))
});