Using arrays as indexedDB keyPaths in IE 10/11 - javascript

I have an array as my keypath using indexedDB and it works fine with Chrome and Firefox, but when I try to add/put using IE it gives me a DataError.
var request = window.indexedDB.open("MyTestDatabase");
request.onsuccess = function(event) {
var database = event.target.result;
var transaction = database.transaction(["document"], "readwrite");
var objectStore = transaction.objectStore("document");
var request = objectStore.put({title: 'MyDoc', version: 0});
request.onsuccess = function() {
console.log('document added');
};
request.error = function(error) {
console.log(JSON.stringify(error));
};
transaction.oncomplete = function() {
console.log('transaction complete');
};
transaction.onerror = function(error) {
console.log(JSON.stringify(error));
};
};
request.onupgradeneeded = function(event) {
event.target.result.createObjectStore("document", {keyPath: ['title', 'version']});
};
Error Screenshot:
How can I keep my double keyPath and get it to work with IE?

The only way to get around this at the moment is to create a string out of the array and use it at the key as Kyaw mentioned.
request.onupgradeneeded = function(event) {
event.target.result.createObjectStore("document", {keyPath: ['id']});
};
The id in the example would now have to be a concatenated string containing the title and version. Some like: MyDoc_0. You'd still store the title and version fields though so you can easily access them without have to split the id string.

Related

Why does indexedDB skip some data when adding to database?

I am using javascript to do this.
I want to add data to the database (indexedDB). The data will be coming from the webservice as json and I am looping through it and adding it to an objectStore with a keyPath.
When I look at the data from the webservice, I have an array of 186 objects but when I read the data from indexedDB, I have 151. When I went to check the database to see if the data was there, it wasn't... So something must be going on with my add function.
Here is my code:
Opening a database with an objectStore:
let db;
let request = window.indexedDB.open("WHS", 4);
request.onerror = function(event) {
console.log(event.target.errorCode);
};
request.onsuccess = function(event) {
db = event.target.result;
};
request.onupgradeneeded = function(event) {
let db = event.target.result;
let palletStore = db.createObjectStore("pallets", { keyPath: "palletno" });
};
Adding data after passing it to my function:
function addPalletsToIDB(pallets) {
let transaction = db.transaction(["pallets"], "readwrite");
let objectStore = transaction.objectStore("pallets");
$.each(pallets, function(i, pallet) {
let request = objectStore.put(pallet);
})
request.onsuccess = function(event) {
console.log('Added pallets : ', event.target.response);
};
transaction.oncomplete = function() {
getPalletDataFromIDB();
}
};
Reading the data:
function getPalletDataFromIDB() {
palletsFromIDB = [];
let transaction = db.transaction(["pallets"], IDBTransaction.READ);
transaction.oncomplete = function(event) {
console.log(event);
};
transaction.onerror = function(event) {
console.log(event.type);
};
let objectStore = transaction.objectStore("pallets");
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
palletsFromIDB.push(cursor.value);
cursor.continue();
}
transaction.oncomplete = function() {
console.log("[palletsFromIDB] ", palletsFromIDB);
toastr.info("Got pallets");
};
};
};
from web service : {pallets: Array(186)}
from indexedDB : [palletsFromIDB] (151)
One way to do this is to just create a unique keyPath in your json and making that your keyPath in indexed db.

IndexedDB: executing function with method add several times - no new DB-entry

I have created a function to store data in indexed db:
var request = window.indexedDB.open("mynewDB", 1);
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore("toDoList", {keyPath: 'key', autoIncrement: true});
var txn = event.target.transaction;
var addRequest = txn.objectStore("toDoList").add({value: storagedata});
}
(FYI: the storagedata is filled with a base64 string)
If i am executing this function via button the content of variable storagedata is in the IndexedDB. But if i want to press the button again to store another value into the IndexedDB, nothing happens.
In addition to that if i am executing the function the second time the function jumps at line request.onupgradeneeded = function(event) { in to the timeout of file "intervalTrigger-dbg.js" to code clearTimeout(this._delayedCallId);
What i did to solve the problem: debugging in browser and reading a lot of documentations about indexeddb.
I fixed the problem on my own.
For everyone who want to know how it works:
var request = window.indexedDB.open("yourDB-1", 1);
var db;
var transaction;
var store;
request.onupgradeneeded = function(event) {
var db = event.target.result;
var transaction = event.target.transaction;
var store = db.createObjectStore("yourDB", {keyPath: 'key', autoIncrement: true});
}
request.onerror = function (event) {
console.log("Here is a error: " + event.target.errorCode);
}
request.onsuccess = function (event) {
db = request.result;
transaction = db.transaction("yourDB", "readwrite");
store = transaction.objectStore("yourDB");
db.onerror = function(event){
console.log("ERROR" + event.target.errorCode);
}
store.put({value: storagedata});
transaction.complete = function() {
db.close();
}
}

How to update object in IndexedDB from service worker

I'm trying to update an Object Store in IndexedDB from a Service Worker, this is my code right now:
function updateUrlLink(url_link) {
var request = indexedDB.open('db', 1);
var url_link_value = url_link;
request.onsuccess = function (event) {
var store = request.result.transaction("url_link", "readwrite").objectStore("url_link");
store.add(url_link_value, "url_link");
};
request.onupgradeneeded = function (event) {
var db = event.target.result;
var store = db.createObjectStore('url_link');
};
}
Is this the right way to update url_link or is there other way?

Can't save blob to indexedDB

I'm having trouble saving blob in IndexedDB, and only with blob.
If I save something else (like image as base64), everything works fine.
But with blob, there is simply empty object property saved.
Screenshot from console:
Code:
//prepared blob...
var openRequest = indexedDB.open("testDB",1);
openRequest.onupgradeneeded = function(e) {
var thisDB = e.target.result;
if(!thisDB.objectStoreNames.contains("stash")) {
thisDB.createObjectStore("stash");
}
}
openRequest.onsuccess = function(e) {
db = e.target.result;
var transaction = db.transaction(["stash"],"readwrite");
var store = transaction.objectStore("stash");
var tID = Date.now();
var obj = {
bl:blob,
created:tID
}
console.log(obj);
//add it
var request = store.add(obj, tID);
request.onerror = function(e) {
console.log("Error",e.target.error.name);
}
request.onsuccess = function(e) {
console.log("success");
}
}
openRequest.onerror = function(e) {
//....
}
I also tried to save only blob (not wrapped as obj property), it's the same.
I can save blob to HDD, and if I console log my obj, I get:
So I guess, blob is valid, and problem is in adding it to indexedDB. I'm new to blob/indexedDB, and probably doing some noob mistake.
Can someone please advise, what am I doing wrong?
PS: no error messages at all
Very old question, but there is support now for saving Blobs in IndexedDb:
https://developers.google.com/web/updates/2014/07/Blob-support-for-IndexedDB-landed-on-Chrome-Dev
// Create an example Blob object
var blob = new Blob(['blob object'], {type: 'text/plain'});
try {
var store = db.transaction(['entries'], 'readwrite').objectStore('entries');
// Store the object
var req = store.put(blob, 'blob');
req.onerror = function(e) {
console.log(e);
};
req.onsuccess = function(event) {
console.log('Successfully stored a blob as Blob.');
};
} catch (e) {
var reader = new FileReader();
reader.onload = function(event) {
// After exception, you have to start over from getting transaction.
var store = db.transaction(['entries'], 'readwrite').objectStore('entries');
// Obtain DataURL string
var data = event.target.result;
var req = store.put(data, 'blob');
req.onerror = function(e) {
console.log(e);
};
req.onsuccess = function(event) {
console.log('Successfully stored a blob as String.');
};
};
// Convert Blob into DataURL string
reader.readAsDataURL(blob);
}
As of posting this, the referenced Document was last updated on: Last updated 2019-03-20 UTC.
You can convert Blob or File object to ArrayBuffer object or binarystring and then save it. Convert it back to Blob after you read from indexedDB.
//prepared blob...
blobToBlob2(blob, saveBlob2);
function blobToBlob2(blob, callback){
var reader = new FileReader();
reader.readAsArrayBuffer(blob);
reader.onload = function(e) {
callback({
buffer: e.target.result,
type: blob.type
});
};
}
function blob2ToBlob(blob2){
return new Blob([blob2.buffer],{type:blob2.type});
}
function saveBlob2(blob2){
//..... code
var obj = {
bl:blob2,
created:tID
}
var request = store.add(obj, tID);
//..... code
}

HTML5 File API: FileReader object is undefined after an error occured

I use Chrome 12 on Mac OS X and I've included jQuery 1.6.1 within the document.
I try to read a File with the following code, an error seams to occur while reading the file, so this.error.onerror() is called, but the FileReader-Object this.reader doesn't exists anymore and I can't get the error. I'm also not sure why the error occurs, it's a regular text document I want to read.
function FileHandler(files, action) {
console.log('FileHandler called.');
this.files = files;
this.reader = new FileReader();
this.action = action;
this.handle = function() {
console.log('FileHandler.handle called.');
for (var i = 0; i < this.files.length; i++) {
this.reader.readAsDataURL(files[i]);
}
}
this.upload = function() {
console.log('FileHandler.upload called.');
console.log(this.reader);
data = {
content: this.reader.result
}
console.log(data);
}
this.error = function() {
console.log('An error occurred while reading a file.');
console.log(this.reader.error);
}
this.reader.onload = this.upload;
this.reader.onerror = this.error;
}
This code creates the following console output:
http://cl.ly/0j1m3j0o3s071Y1K3A25
Inside .onerror, the this is not the same as outside because it's a new function (with a new scope).
Keep track of the this by setting it statically like this:
var _this = this; // _this won't change
this.reader.onerror = function() {
console.log('An error occurred while reading a file.');
console.log(_this.reader.error);
}
This should be the correct way to do it:
reader.onerror = function(event) {
console.error("File could not be read: " + event.target.error);
};

Categories