how to pass callback to onerror method globally? - javascript

i have a piece of code for IndexedDB
GetObj = function(storeName, key, callback){
var db = indexedDB.db;
if(db){
var transaction = db.transaction([storeName], transactionType.READ_ONLY);
var obj = undefined;
transaction.oncomplete = function(event) {
if(callback){
callback(obj);
}
};
var objectStore = transaction.objectStore(storeName);
var request = objectStore.get(key);
request.onerror = function (e){
console.log("onError: in", e);
if (callback) {
callback(-1);//error
}
}
request.onsuccess = function(event) {
obj = request.result;
};
}
}
I would like to define the request.onerror function globally so that i can reuse that function for all onerror (instead of copy pasting it all over the place). problem is howto pass callback?

Just define it in a higher scope:
var onerrorHandler = function (e, callback){
console.log("onError: in", e);
if (callback) {
callback(-1);//error
}
};
And then use that for the callback:
... snip
var request = objectStore.get(key);
request.onerror = function (e) {
onerrorHandler(e, callback);
};
... snip

I will rather avoid global error handler.
As you see, the code is not really reduce, but expended to include another wrapper function. In doing so, the error stack trace is not telling which request is causing error.

Related

Is it possible to modify XMLHttpRequest.prototype.open()?

I am trying to inject callbacks into XMLHttpRequest.prototype.open() so I can know the method and the url, as well as setting a timestamp for the performance report (alone with the modified XMLHttpRequest.prototype.send()).
Here is what I came up so far:
function addXMLRequestCallback(open, callback) {
var nativeOpen, nativeSend, i;
if (XMLHttpRequest.callbacks) {
XMLHttpRequest.callbacks.push(callback);
} else {
XMLHttpRequest.callbacks = [callback];
nativeOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
open.forEach(function(item) {
// not sure what to do here...
});
}
nativeSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
for (i = 0; i < XMLHttpRequest.callbacks.length; i++) {
XMLHttpRequest.callbacks[i](this);
}
nativeSend.apply(this, arguments);
}
}
}
addXMLRequestCallback(function(method,url){
// Maybe instead I should put code here...
}, function(xhr) {
// then do something here?
});
What you had with the send method was the right approach. In the following snippet, I only inplemented a listener that gets called whenever an XMLHttpRequest's open method is called. I'm sure you can implement the same for send.
(function () {
var nativeOpen = XMLHttpRequest.prototype.open;
var callbacks = XMLHttpRequest.callbacks = [];
XMLHttpRequest.prototype.open = function () {
callbacks.forEach(callback => callback.apply(this, arguments));
nativeOpen.apply(this, arguments);
};
})();
function addXHROpenCallback (cb) {
XMLHttpRequest.callbacks.push(cb);
}
addXHROpenCallback(function (method, url) {
console.log(`XHR opened. Method: ${method}, URL: ${url}`);
});
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com');
However, ask yourself if you really need to modify a built-in prototype. Consider creating a wrapper class that does the same, but without modifying a prototype.

IndexedDB how to read element?

I am trying to save a key if it doesn't exists and if it does- just read it.
But it always alerts undefined.
var idb = window.indexedDB.open('MyDB', 1);
idb.onupgradeneeded = function(e)
{
var db = e.target.result;
if (!db.objectStoreNames.contains('all'))
{
db.createObjectStore('all');
}
}
idb.onsuccess = function(e)
{
db = e.target.result;
setData();
}
function setData()
{
var store = db.transaction(['all'], 'readwrite').objectStore('all');
var item1 = {theTitle: 'myKey', theValue: 'myValue'};
var op = store.get('myKey');
op.onsuccess = function(event)
{
alert(op.result);
}
op.onerror = function()
{
var req = store.add(item1, 1);
req.onsuccess = function()
{
alert('Saved');
}
}
}
IDBObjectStore will return undefined if it can't find anything, so your op.onsuccess function is actually working correctly.
See here: http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-get-IDBRequest-any-key
You can place your "store.add" code in your onsuccess function:
var transaction = db.transaction(['all'], 'readwrite');
var store = transaction.objectStore('all');
var item1 = {
theTitle: 'myKey',
theValue: 'myValue'
};
var op = store.get('myKey');
op.onsuccess = function(event) {
if (op.result) {
alert(op.result);
} else {
var req = store.add(item1, 1);
req.onsuccess = function() {
alert('Saved');
}
}
}
transaction.oncomplete = function(event) {
console.log("Transaction complete. Everything is saved.")
}
Also look at the transaction.complete, onerror and onabort functions - they provide you with a better place to do dump all your error handling.
I would advise you to read the IDB spec: it's seems longwinded at first, but you get used to it and it's the best document there is on IDB.
http://www.w3.org/TR/IndexedDB/
Have fun!

IndexedDB open DB request weird behavior

I have an app (questionnaire) that uses indexedDB.
We have one database and several stores in it.
Stores have data already stored in them.
At some point a dashboard html file is loaded. In this file I am calling couple of functions:
function init(){
adjustUsedScreenHeight();
db_init();
setInstitutionInstRow();
loadRecommendations();
loadResultsFromDB();
fillEvaluations();
document.addEventListener("deviceready", onDeviceReady, function(e) {console.log(e);});
}
The init() function is called on body onLoad.
setInstitutionInstRow() looks like these:
function setInstitutionInstRow(localId){
//localId = 10;
if (localId == undefined){
console.log("Localid underfined: ");
//open db, open objectstore;
var request = indexedDB.open("kcapp_db", "1.0");
request.onsuccess = function() {
var db = request.result;
var tx = db.transaction ("LOCALINSTITUTIONS", "readonly");
var store = tx.objectStore("LOCALINSTITUTIONS");
tx.oncomplete = function(){
db.close();
}
tx.onerror = function(){
console.log("Transaction error on setInstInstRow");
}
var cursor = store.openCursor();
cursor.onsuccess= function () {
var match = cursor.result;
console.log ("Retrieved item: " + match.value.instid);
// alert("Added new data");
if (match){
setInstituionInstRow(match.value.instid);
console.log("Got localid: " + math.value.instid);
}
else
console.log("localinsid: it is empty " );
};
cursor.onerror = function () {
console.log("Error: " + item.result.errorCode);
}
}
request.onerror = function () {
console.log("Error: " + request.result.errorCode );
}
request.oncomplete = function (){
console.log("The transaction is done: setInstitutionRow()");
}
request.onupgradeneeded = function (){
console.log("Upgrade needed ...");
}
request.onblocked = function(){
console.log("DB is Blocked ...");
}
} else {
instid = localId;
var now = new Date();
//console.log("["+now.getTime()+"]setInstituionInstRow - instid set to "+localId);
//open db, open objectstore;
var request = indexedDB.open("kcapp_db", "1.0");
request.onsuccess = function() {
var db = this.result;
var tx = db.transaction ("INSTITUTIONS", "readonly");
var store = tx.objectStore("INSTITUTIONS");
var item = store.get(localId);
console.log(item);
item.onsuccess= function () {
console.log ("Retrieved item: ");
if (item.length > 0)
var lInstitution = item.result.value;
kitaDisplayValue = lInstitution.krippe;
};
item.onerror = function () {
console.log("Error: " + item.result.errorCode);
}
}
request.onerror = function () {
console.log("Error: " + request.result.errorCode );
}
}
Now the problem is,
var request = indexedDB.open("kcapp_db", "1.0");
the above request is never getting into any onsuccess, oncomplete, onerror states. I debugged with Chrome tools, it never getting into any above states.
Accordingly I am not getting any data from transactions.
And there are no errors in Chrome console.
And here is the request value from Chrome dev:
From above image the readyState: done , which means it should fire an event (success, error, blocked etc). But it is not going into any of them.
I am looking into it, and still can not figure out why it is not working.
Have to mention that the other functions from init() is behaving the same way.
Looking forward to get some help.
You may be using an invalid version parameter to the open function. Try indexedDB.open('kcapp_db', 1); instead.
Like Josh said, your version parameter should be an integer, not a string.
Your request object can get 4 events in response to the open request: success, error, upgradeneeded, or blocked. Add event listeners for all of those (e.g. request.onblocked = ...) and see which one is getting fired.
I had that problem but only with the "onupgradeneeded" event. I fixed it changing the name of the "open" function. At the begining I had a very long name; I changed it for a short one and start working. I don't know if this is the real problem but it was solved at that moment.
My code:
if (this.isSupported) {
this.openRequest = indexedDB.open("OrdenesMant", 1);
/**
* Creación de la base de datos con tablas y claves primarias
*/
this.openRequest.onupgradeneeded = function(oEvent) {
...
Hope it works for you as well.

indexedDB openCursor transaction onsuccess returns empty array

req = db.openCursor();
req.customerData=new Array() //[{a:1}]
req.onsuccess = function(e) {
var cursor = e.currentTarget.result;
if (cursor) {
//console.log(cursor.value);
e.currentTarget.customerData.push(cursor.value);
e.currentTarget.customerData.push("hello?");
cursor.continue()
}
else {
console.log(e.currentTarget.customerData) //this always correct
}
}
console.log(req.customerData); //outside the onsuccess everything is gone?
console.log(req);
I can see customerData when I open the object in the chrome console
console.log(req.customerData);
But when I do the above it is empty?
replacing new Array() with [{a:1}]
console.log(req.customerData);
I can see a and also the other objects
but then agian
console.log(req.customerData[0].a);
works and the other objects are gone.
How can I save customerData? I tried just pushing numbers or text but same thing after transaction is done. I can't get the data out only display it on console.log() during the transaction?
I know it must be something past by reference but every variable I trow in dissapears?
Added full example below just type write() and read() in console
<script>
var iDB
ready=function(){
var request = indexedDB.open("my-database",1);
request.onupgradeneeded = function(e) {
var db = e.currentTarget.result
var store = db.createObjectStore("store", {keyPath: "muts", autoIncrement:false})
//store.createIndex("by_submit", "submit", {unique: false})
console.log('db upgrade', 'v'+db.version)
}
request.onerror = function(e) {
//var db = e.currentTarget.result;
//db.close()
console.error('db error ',e)
}
request.onsuccess = function(e) {
var db = e.currentTarget.result
db.onversionchange = function(e) {
db.close()
console.log('db changed', 'v'+db.version, 'CLOSED')
}
console.log('db setup', 'v'+db.version, 'OK')
}
iDB=request
}
drop=function(){
iDB.result.close()
var req = indexedDB.deleteDatabase(this.iDB.result.name);
req.onsuccess = function() {console.log("Deleted database successfully")}
req.onerror = function() {console.log("Couldn't delete database")}
req.onblocked = function() {console.log("Couldn't delete database due to the operation being blocked")}
}
read=function(){
var db=iDB
.result
.transaction(["store"], "readwrite").objectStore("store");
var req = db.openCursor();
req.iData=new Array();
req.onsuccess = function(e) {
var cursor = e.currentTarget.result;
if (cursor) {
e.currentTarget.iData.push(cursor.value);
e.currentTarget.iData.push("hello");
cursor.continue()
}
else {
console.log(e.currentTarget.iData)
}
}
console.log(req.iData)
}
write=function(){
var db=document.querySelector('my\-database')
.iDB
.result
.transaction(["store"], "readwrite").objectStore("store");
var customerData = [
{muts: "Bill", qty: "1"},
{muts: "Donna", qty: "1"}
]
for (var i in customerData){db.put(customerData[i])}
}
ready()
</script>
A few things
I recommend not setting custom properties of an IDBRequest object. Create and access objects that are in an outer scope instead.
There is no need to use event.currentTarget. event.target is sufficient (and so is 'this', and so is the request object itself).
onversionchange is deprecated.
Due to the asynchronous nature of indexedDB, you may be trying to print something out to the console that does not yet exist, or no longer exists. Instead, try printing something out when the transaction completes.
For example:
function populateArray(openDatabaseHandle, onCompleteCallbackFunction) {
var transaction = openDatabaseHandle.transaction('store');
var store = transaction.objectStore('store');
var myArray = [];
var request = store.openCursor();
request.onsuccess = function() {
var cursor = this.result;
if(!cursor) return;
myArray.push(cursor.value);
cursor.continue();
};
transaction.oncomplete = function() {
onCompleteCallbackFunction(myArray);
};
}
// An example of calling the above function
var conn = indexedDB.open(...);
conn.onsuccess = function() {
populateArray(this.result, onPopulated);
};
// An example of a callback function that can be passed to
// the populateArray function above
function onPopulated(data) {
console.debug(data);
data.forEach(function(obj) {
console.debug('Object: %o', obj);
});
}

generic async callback function

this.init = function (onupgradeneeded, onsuccess) {
var openRequest = indexedDB.open(dbName);
openRequest.onupgradeneeded = function (e) {
db = e.target.result;
if (!db.objectStoreNames.contains(objectStoreName)) {
console.log('Creating the ' + objectStoreName + ' objectstore');
db.createObjectStore(objectStoreName, { keyPath: "id", autoIncrement: true });
}
};
openRequest.onsuccess = function (e) {
db = e.target.result;
db.onerror = function (event) {
// Generic error handler for all errors targeted at this database requests
console.log("Database error: " + event.target.errorCode);
};
};
};
Called by:
var idb = new Demo.IndexedDB();
idb.init();
When the init function runs, it will either end up in openRequest.onupgradeneeded or openRequest.onsuccess.
What i would like to know is if its possible to create a generic callback function that gets called in both function. So regardless of which of the two functions that runs i can know when theyre done by using
idb.init(function(){
//onupgradeneeded or onsuccess completed
});
Hope you get the idea, otherwise ill elaborate.
Thanks
Just pass in one callback function and call that one single callback in both cases:
this.init = function (onFinish) {
var openRequest = indexedDB.open(dbName);
openRequest.onupgradeneeded = function (e) {
db = e.target.result;
if (!db.objectStoreNames.contains(objectStoreName)) {
console.log('Creating the ' + objectStoreName + ' objectstore');
db.createObjectStore(objectStoreName, { keyPath: "id", autoIncrement: true });
}
onFinish();
};
openRequest.onsuccess = function (e) {
db = e.target.result;
db.onerror = function (event) {
// Generic error handler for all errors targeted at this database requests
console.log("Database error: " + event.target.errorCode);
};
onFinish();
};
};

Categories

Resources