IndexedDB how to read element? - javascript

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!

Related

How to add initial data in indexeddb only once

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

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

Why is db.transaction not working with indexeddb?

I am new at using inxededdb and am trying to get data out of a store. The store contains data, but for some reason the code stops after trying to set the var tx. If I am missing anything please let me know. Here is the function with which I am trying to get the book:
function getBook(){
var tx = db.transaction("book", "readonly");
var store = tx.objectStore("book");
var index = store.index("by_getid");
var request = index.get("<?php echo $_GET['book'] ?>");
request.onsuccess = function() {
var matching = request.result;
if (matching !== undefined) {
document.getElementById("text-container").innerHTML = matching.text;
} else {
alert('no match');
report(null);
}
};
}
Solved Version:
function getBook(){
var db;
var request = indexedDB.open("library", 1);
request.onsuccess = function (evt) {
db = request.result;
var transaction = db.transaction(["book"]);
var objectStore = transaction.objectStore("book");
var requesttrans = objectStore.get(<?php echo $_GET['book'] ?>);
requesttrans.onerror = function(event) {
};
requesttrans.onsuccess = function(event) {
alert(requesttrans.result.text);
};
};
}
The problem is probably your db variable. You are probably accessing a closed or null instance of a connection object.
Try instead to create the db connection right inside the function. Do NOT use a global db variable.
index.get yields primary key. You have to get record value using the resulting primary key.
I has problem with transaction, it's return error db.transaction is not a function or return undefined.
You will try like this, it's working for me:
const table = transaction.objectStore('list');
const query = table.getAll();
query.onsuccess = () => {
const list = query?.result;
console.log(list);
};

Post header in extension firefox

Iam building an extension where i catch all the post requests. But in the httpChannel.originalURI.spec there aren't any attributes from the post. How can i get the post's atrtibutes?
myObserver.prototype = {
observe: function(subject, topic, data) {
if("http-on-modify-request"){
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
if(httpChannel.requestMethod=="POST")
alert(httpChannel.originalURI.spec);
}
}
},
register: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(this, "http-on-modify-request", false);
},
unregister: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(this, "http-on-modify-request");
}
}
Any ideas?
nsIHttpChannel only provides access to HTTP headers. POST data is sent as part of the request body so you need to change your object interface to nsIUploadChannel and read the binary upload data into a string.
var uploadChannel = httpChannel.QueryInterface(Ci.nsIUploadChannel);
var uploadStream = uploadChannel.uploadStream;
uploadStream.QueryInterface(Ci.nsISeekableStream).
seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
var binStream = Cc["#mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIBinaryInputStream);
binStream.setInputStream(uploadStream);
var postBytes = binStream.readByteArray(binStream.available());
var postString = String.fromCharCode.apply(null, postBytes);
The code from Luckyrat did not work properly for me. I had to deal with some requests timing out. Noticing nmaiers comment this code is working correctly (as far as I can tell):
function getPostString(httpChannel) {
var postStr = "";
try {
var uploadChannel = httpChannel.QueryInterface(Ci.nsIUploadChannel);
var uploadChannelStream = uploadChannel.uploadStream;
if (!(uploadChannelStream instanceof Ci.nsIMultiplexInputStream)) {
uploadChannelStream.QueryInterface(Ci.nsISeekableStream).seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
var stream = Cc["#mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
stream.setInputStream(uploadChannelStream);
var postBytes = stream.readByteArray(stream.available());
uploadChannelStream.QueryInterface(Ci.nsISeekableStream).seek(0, 0);
postStr = String.fromCharCode.apply(null, postBytes);
}
}
catch (e) {
console.error("Error while reading post string from channel: ", e);
}
finally {
return postStr;
}
}

Public methods in javascript OOP

I want to make a javascript class with methods which I can call within the class as well as outside of the class. I want to make a "public" method, if you will. I want getTextAreaElement and appendTextArea to be such methods.
I've shown a snippet of best code I could come up with so far. I've also tried defining the methods as prototypes as well as within the class (this.func = ...). But that only allowed me to call the method outside (new Socket().appendTextArea("osgjr89");) but NOT within the class itself! The code snippet below shows the exact opposite implementation where I can't call the method outside of the class but can call it within.
Error:
Uncaught TypeError: Object #Socket has no method 'appendTextArea'
socket.js:
function Socket() {
var socket;
var canvas = document.getElementById('c');
var context = canvas.getContext("2d");
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:9012/websocket");
socket.binaryType = 'arraybuffer';
socket.onopen = onopen;
socket.onmessage = onmessage;
socket.onerror = onerror;
socket.onclose = onclose;
} else {
alert("Your browser does not support Web Socket.");
}
function getTextAreaElement() {
return document.getElementById('responseText');
}
function appendTextArea(newData) {
var el = getTextAreaElement();
el.value = el.value + '\n' + newData + " :)";
}
function onopen(event) {
getTextAreaElement().value = "Web Socket opened!";
}
/*[...]*/
}
main.js (loads after socket.js)
$(document).ready(function() {
var s = new Socket();
s.appendTextArea("osgjr89"); // ERROR!
});
UPDATED socket.js:
function Socket() {
[...]
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:9012/websocket");
socket.binaryType = 'arraybuffer';
socket.onopen = this.onopen;
socket.onmessage = this.onmessage;
socket.onerror = this.onerror;
socket.onclose = this.onclose;
} else {
alert("Your browser does not support Web Socket.");
}
this.getTextAreaElement = function() {
return document.getElementById('responseText');
}
this.appendTextArea = function(newData) {
var el = this.getTextAreaElement();
el.value = el.value + '\n' + newData + " :)";
}
this.onopen = function(event) {
this.getTextAreaElement().value = "Web Socket opened!";
}
[...]
}
All public methods must be declared as properties, not variables/functions. So, you have to change stuff like this:
function getTextAreaElement() {
return document.getElementById('responseText');
}
into
this.getTextAreaElement = function() {
return document.getElementById('responseText');
}
If you do this.func = function() {}, you can call the function inside the Constructor (Socket in your case) using this.func() as well as outside using:
var s = new Socket();
s.func();

Categories

Resources