I am trying to create a service worker for uploading files to the server, but getting an error
Failed to execute 'transaction' on 'IDBDatabase': One of the specified object stores was not found.
I am trying that when a user uploads a file and if the internet is slow or the user closes the window while uploading, the data will be in the queue, and once available it should start uploading in the background.
function addToQueue(request) {
return new Promise(function (resolve, reject) {
// Open an IndexedDB database and store the file in the Que object store
var openRequest = indexedDB.open("uploadQueue", 1);
openRequest.onupgradeneeded = function () {
var db = openRequest.result;
db.createObjectStore("queue", { autoIncrement: true });
};
openRequest.onsuccess = function () {
var db = openRequest.result;
var transaction = db.transaction(["queue"], "readwrite");
var objectStore = transaction.objectStore("queue");
objectStore.add(request);
transaction.oncomplete = function () {
db.close();
resolve();
};
};
});
}
setInterval(function () {
if (navigator.onLine) {
// Check if there are any queued files
var openRequest = indexedDB.open("uploadQueue", 1);
openRequest.onsuccess = function () {
var db = openRequest.result;
var transaction = db.transaction(["queue"], "readonly");
var objectStore = transaction.objectStore("queue");
var request = objectStore.getAll();
request.onsuccess = function () {
// If there are queued file, start uploading them
if (request.result.length > 0) {
request.result.forEach(function (request) {
fetch("https://abc.in/serviceworker/", {
method: "POST",
body: request.body,
});
objectStore.delete(request.id);
});
}
};
};
}
}, 60000);
Related
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!
I am creating an indexeddb, and have several stores in it.
Have some data that has to be initially added when stores are created.
I have function where I create database and stores:
function db_init(){
var request = indexedDB.open("db", "1.0");
request.onupgradeneeded = function(){
var db = request.result;
//store 1
db.createObjectStore("store1", {keypath: "id", autoIncrement: true});
//add initial datas;
//store2
db.createObjectStore("store2", {keypath: "id", autoIncrement: true});
//...
//store 3
// init necessary databases
db_populate();
}
request.onsuccess = function (){
db = request.result;
populate:db();
}
}
And inside db_populate function have 4 other functions where I am populating datastores:
function db_populate() {
init_store1();
init_store2();
//...
console.log("db populated with data");
}
Each init_score populates stores with transactions like below:
var tx = db.transaction("store1", "readwrite");
var store = tx.objectStore("store1");
Now, I have a problem. Every time I open or refresh the page, the initial data are duplicated. There are added over again.
When I add db_populate at the end of onupgradeneeded function, I get an error:
Uncaught TypeError: Cannot read property 'transaction' of undefined
on line:
var tx = db.transaction ("store1", "readwrite");
What I am trying to achieve is to create data stores with its initial data once and that is it.
Any idea what I am doing wrong?
Thanks in advance.
That's due to the fact that you can't insert data during a upgrade needed event. What you need to do instead is close the connection after the upgrade and reopen it again for the data insert.
The flow should be something like this:
function db_init() {
var request = indexedDB.open("db");
var dbShouldInit = false;
request.onupgradeneeded = function(e) {
var db = e.target.result;
dbShouldInit = true;
//store 1
db.createObjectStore("store1", {
keypath: "id",
autoIncrement: true
});
//add initial datas;
//store2
db.createObjectStore("store2", {
keypath: "id",
autoIncrement: true
});
}
request.onsuccess = function(e) {
e.target.result.close();
if(dbShouldInit)//executes only if DB init happened
db_populate(); //close the db first and then call init
}
}
function db_populate() {
init_store1(init_store2); //pass init 2 as callback
}
function init_store1(callback) {
var request = indexedDB.open("db");
request.onsuccess = function(e) {
var db = e.target.result;
var tx = db.transaction("store1", "readwrite");
var store = tx.objectStore("store1");
//init code here
tx.oncomplete = function(e) {
callback(); //here call the init for second function
};
}
}
function init_store2() {
var request = indexedDB.open("db");
request.onsuccess = function(e) {
var db = e.target.result;
var tx = db.transaction("store2", "readwrite");
var store = tx.objectStore("store2");
//init code here
tx.oncomplete = function(e) {
//here the app can continue
};
}
}
(function () {
//indexedDB.deleteDatabase("store");
var openDB = indexedDB.open("store", 1);
openDB.onupgradeneeded = function () {
var db = openDB.result;
var store;
if (!db.objectStoreNames.contains("example")) {
store = db.createObjectStore("example", {keyPath: "some"});
store.put({some: "initData"});
}
};
openDB.onsuccess = function (e) {
var db = e.target.result;
var rqst = db.transaction("example", "readonly")
.objectStore("example")
.get("initData");
rqst.onsuccess = function (e) {
console.log(rqst.result);
};
};
})();
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);
});
}
I'm trying to write an object with member functions for receiving and sending data to and from the client with Node JS and Socket IO. The problem is that every time I send data from the client, there is a new 'connection' event that fires. Is that how it works? I thought the connection event would only occur on a new connection. So with the code below, the log echoes 'New connection' with every reception from the client. It doesn't seem right.
io.sockets.on('connection', function (socket) {
console.log('New connection');
var localSocket = socket;
var newsock = new UserSocket(localSocket);
newsock.game = null;
newsock.host = null;
newsock.opponent = null;
newsock.room = "";
newsock.SendToHostSocket('Welcome to Baseball Strategy II');
arrSockets.push(socket);
});
function UserSocket(sock) {
var localSock = sock;
var o = this;
this.sock = localSock;
this.sock.on('clientData', function (data) {
console.log("user socket object");
console.log(o);
o.ParseClientData(data);
});
}
This is a simplified version of what I have for the client:
$(document).ready( function () {
var socket = io.connect('http://local.baseball.com:3333');
function SocketGameOut(outstring) {
socket.emit('clientData', outstring );
}
$("#hostGame").click( function () {
var gamenum = $('input[name=gameSelect]:checked', '#gameForm').val();
var aSendData = { command : "newgame" , senddata : { gameid : gamenum } };
var senddata = JSON.stringify(aSendData);
SocketGameOut(senddata);
});
});
Modify your code as below it worked for me.
//use once.('connection') instead of on.('connection')
io.sockets.once('connection', function (socket) {
console.log('New connection');
var localSocket = socket;
var newsock = new UserSocket(localSocket);
newsock.game = null;
newsock.host = null;
newsock.opponent = null;
newsock.room = "";
newsock.SendToHostSocket('Welcome to Baseball Strategy II');
arrSockets.push(socket);
});
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();
};
};