IndexedDB Reference Error: db is not defined - javascript

I'm trying to create an application for Firefox OS which basically needs to store some data using IndexedDB.
The store() function is called when the user clicks on a submit button which results in the creation of the name and description variables an user submitted form.
However, I keep getting a Reference Error saying my db object is not defined. Any ideas why this is happening?
Here's my current code:-
function store () {
// create the transaction with 1st parameter is the list of stores and the second specifies
// a flag for the readwrite option
var transaction = db.transaction([ 'Apps' ], 'readwrite');
//Create the Object to be saved i.e. our App details
var value = {};
value.name = name;
value.desc = description;
// add the details to the store
var store = transaction.objectStore('Apps');
var request = store.add(value);
request.onsuccess = function (e) {
alert("Your App data has been saved");
};
request.onerror = function (e) {
alert("Error in saving the App data. Reason : " + e.value);
}
}
$(document).ready(function(){
// variable which will hold the database connection
var db;
if (window.indexedDB) {
console.log("IndexedDB is supported");
}
else {
alert("Indexed DB is not supported!");
}
// open the database
// 1st parameter : Database name. We are using the name 'Appsdb'
// 2nd parameter is the version of the database.
var request = indexedDB.open('Appsdb', 1);
request.onsuccess = function (e) {
// e.target.result has the connection to the database
db = e.target.result;
console.log(db);
console.log("DB Opened!");
}
request.onerror = function (e) {
console.log(e);
};
// this will fire when the version of the database changes
// We can only create Object stores in a versionchange transaction.
request.onupgradeneeded = function (e) {
// e.target.result holds the connection to database
db = e.target.result;
if (db.objectStoreNames.contains("Apps")) {
db.deleteObjectStore("Apps");
}
// create a store named 'Apps'
// 1st parameter is the store name
// 2nd parameter is the key field that we can specify here. Here we have opted for autoIncrement but it could be your
// own provided value also.
var objectStore = db.createObjectStore('Apps', { keyPath: 'id', autoIncrement: true });
console.log("Object Store has been created");
};
});

The problem is with the scope of the db variable. Currently you have the following line var db; declared inside of the $(document).ready function. Move its declaration to a more global scope i.e. outside of this function and the variable will be visible in the store() function too.
Hope this helps.

var value = {};
value.name = name;
value.desc = description;
assign value to the name and description.
name=formname.name.value
description=formname.description.value

Related

Get specifics ids in IndexedDB [duplicate]

I want to execute this query
select * from properties where propertyCode IN ("field1", "field2", "field3")
How can I achieve this in IndexedDB
I tried this thing
getData : function (indexName, params, objectStoreName) {
var defer = $q.defer(),
db, transaction, index, cursorRequest, request, objectStore, resultSet, dataList = [];
request = indexedDB.open('test');
request.onsuccess = function (event) {
db = request.result;
transaction = db.transaction(objectStoreName);
objectStore = transaction.objectStore(objectStoreName);
index = objectStore.index(indexName);
cursorRequest = index.openCursor(IDBKeyRange.only(params));
cursorRequest.onsuccess = function () {
resultSet = cursorRequest.result;
if(resultSet){
dataList.push(resultSet.value);
resultSet.continue();
}
else{
console.log(dataList);
defer.resolve(dataList);
}
};
cursorRequest.onerror = function (event) {
console.log('Error while opening cursor');
}
}
request.onerror = function (event) {
console.log('Not able to get access to DB in executeQuery');
}
return defer.promise;
But didn't worked. I tried google but couldn't find exact answer.
If you consider that IN is essentially equivalent to field1 == propertyCode OR field2 == propertyCode, then you could say that IN is just another way of using OR.
IndexedDB cannot do OR (unions) from a single request.
Generally, your only recourse is to do separate requests, then merge them in memory. Generally, this will not have great performance. If you are dealing with a lot of objects, you might want to consider giving up altogether on this approach and thinking of how to avoid such an approach.
Another approach is to iterate over all objects in memory, and then filter those that don't meet your conditions. Again, terrible performance.
Here is a gimmicky hack that might give you decent performance, but it requires some extra work and a tiny bit of storage overhead:
Store an extra field in your objects. For example, plan to use a property named hasPropertyCodeX.
Whenever any of the 3 properties are true (has the right code), set the field (as in, just make it a property of the object, its value is irrelevant).
When none of the 3 properties are true, delete the property from the object.
Whenever the object is modified, update the derived property (set or unset it as appropriate).
Create an index on this derived property in indexedDB.
Open a cursor over the index. Only objects with a property present will appear in the cursor results.
Example for 3rd approach
var request = indexedDB.open(...);
request.onupgradeneeded = upgrade;
function upgrade(event) {
var db = event.target.result;
var store = db.createObjectStore('store', ...);
// Create another index for the special property
var index = store.createIndex('hasPropCodeX', 'hasPropCodeX');
}
function putThing(db, thing) {
// Before storing the thing, secretly update the hasPropCodeX value
// which is derived from the thing's other properties
if(thing.field1 === 'propCode' || thing.field2 === 'propCode' ||
thing.field3 === 'propCode') {
thing.hasPropCodeX = 1;
} else {
delete thing.hasPropCodeX;
}
var tx = db.transaction('store', 'readwrite');
var store = tx.objectStore('store');
store.put(thing);
}
function getThingsWherePropCodeXInAnyof3Fields(db, callback) {
var things = [];
var tx = db.transaction('store');
var store = tx.objectStore('store');
var index = store.index('hasPropCodeX');
var request = index.openCursor();
request.onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
var thing = cursor.value;
things.push(thing);
cursor.continue();
} else {
callback(things);
}
};
request.onerror = function(event) {
console.error(event.target.error);
callback(things);
};
}
// Now that you have an api, here is some example calling code
// Not bothering to promisify it
function getData() {
var request = indexedDB.open(...);
request.onsuccess = function(event) {
var db = event.target.result;
getThingsWherePropCodeXInAnyof3Fields(db, function(things) {
console.log('Got %s things', things.length);
for(let thing of things) {
console.log('Thing', thing);
}
});
};
}

Use of indexedDB returns 'undefined'

I'm trying to use indexedDB.
Some parts of my code works.
In the following example, the first function adds server in my DB, however in Chrome debug console there is an undefined message not related to any line. The server is already added though.
The second function puts records in an array, there is also an undefined message not related to any line.
If I do a console.log(servers); just before return servers; I can see the array content, however if I call the function somewhere else in my code, the returned object is undefined.
var dbName = 'myDBname',
dbServersStoreName = 'servers',
dbVersion = 1,
openDBforCreation = indexedDB.open(dbName, dbVersion);
openDBforCreation.onupgradeneeded = function(e) {
var db = e.target.result;
var objStore = db.createObjectStore(dbServersStoreName, { keyPath: "alias"
});
var index = objStore.createIndex("serversAlias", ["alias"]);
};
function addServerInDB(serverAlias,serverAddress,user,pwd){
var myDB = indexedDB.open(dbName, dbVersion);
myDB.onerror = function() {
var notification = document.querySelector('.mdl-js-snackbar');
notification.MaterialSnackbar.showSnackbar(
{message: 'Error while trying to access internal database'});
}
myDB.onsuccess = function(e) {
var db = e.target.result,
request = db.transaction([dbServersStoreName],
"readwrite").objectStore("servers")
.put({alias:''+serverAlias+'',
address:''+serverAddress+'', login:''+user+'',
passwd:''+pwd+''});
request.onsuccess = function(){
var notification = document.querySelector('.mdl-js-snackbar');
notification.MaterialSnackbar.showSnackbar(
{message: 'Server added'});
}
}
};
function listServersInDB(){
var myDB= indexedDB.open(dbName, dbVersion);
myDB.onerror = function() {
var notification = document.querySelector('.mdl-js-snackbar');
notification.MaterialSnackbar.showSnackbar(
{message: 'Error while trying to access internal database'});
}
myDB.onsuccess = function(e) {
var servers = new Array(),
db = e.target.result,
request = db.transaction(["servers"], "readwrite")
.objectStore("servers")
.openCursor();
request.onsuccess = function(e){
var cursor = e.target.result;
if(cursor){
servers.push(cursor.value);
cursor.continue();
}
return servers;
}
}
};
I do not understand where this undefined comes from and if that is why the listServersInDB() function doesn't work.
You need to learn more about how to write asynchronous Javascript. There are too many errors in your code to even begin reasoning about the problem.
Briefly, don't do this:
function open() {
var openDatabaseRequest = ...;
}
openDatabaseRequest.foo = ...;
Instead, do this:
function open() {
var openDatabaseRequest = ...;
openDatabaseRequest.foo = ...;
}
Next, you don't need to try and open the same database multiple times. Why are you calling indexedDB.open twice? You can open a database to both install it and to start using it immediately. All using the same connection.
Next, I'd advise you don't name the database open request as 'myDB'. This is misleading. This is an IDBRequest object, and more specifically, an IDBOpenRequest object. A request isn't a database.
Next, you cannot return the servers array from the request.onsuccess at the end. For one this returns to nowhere and might be source of undefined. Two this returns every single time the cursor is advanced, so it makes no sense at all to return return servers multiple times. Three is that this returns too early, because it cannot return until all servers enumerated. To properly return you need to wait until all servers listed. This means using an asynchronous code pattern. For example, here is how you would do it with a callback:
function listServers(db, callbackFunction) {
var servers = [];
var tx = db.transaction(...);
var store = tx.objectStore(...);
var request = store.openCursor();
request.onsuccess = function() {
var cursor = request.result;
if(cursor) {
servers.push(cursor.value);
cursor.continue();
}
};
tx.oncomplete = function() {
callbackFunction(servers);
};
return 'Requested servers to be loaded ... eventually callback will happen';
}
function connectAndList() {
var request = indexedDB.open(...);
request.onsuccess = function() {
var db = request.result;
listServers(db, onServersListed);
};
}
function onServersListed(servers) {
console.log('Loaded servers array from db:', servers);
}
When you call a function that does not return a value, it returns undefined. All functions in JavaScript return undefined unless you explicitly return something else.
When you call a function from the devtools console, and that function returns undefined, then the console prints out '-> undefined'. This is an ordinary aspect of using the console.
If you want to get a function that returns the list of servers as an array, well, you cannot. The only way to do that in a pretend sort of way, is to use an 'async' function, together with promises.
async function getServers() {
var db = await new Promise(resolve => {
var request = indexedDB.open(...);
request.onsuccess = () => resolve(request.result);
});
var servers = await new Promise(resolve => {
var tx = db.transaction(...);
var request = tx.objectStore(...).getAll();
request.onsuccess = () => resolve(request.result);
});
return servers;
}
One more edit, if you want to call this from the console, use await getServers();. If you do not use the top-level await in console, then you will get the typical return value of async function which is a Promise object. To turn a promise into its return value you must await it.
Clear and helpfull explanations, Thank you.
I open database multiple times beacause the first time is for checking if DB needs an upgrade and doing something if needed. I'll add 'db.close()' in each functions.
Then, I tried your exemple and the result is the same:
console.log('Loaded servers array from db:', servers); works
but return servers; Don't work.
And in console there is already an undefined without related line :
Screenshot

Not able to save a custom class object in Parse

I am trying to create a Customer class object which has a one to one relation with the User class. But the object doesn't save without giving any error.
Here is my code:
Parse.Cloud.afterSave(Parse.User, function(request) {
user = request.object;
role_name = user.get("role_name");
user_name = user.get("user_name");
user_id = user.get("objectId");
if (role_name == "customer"){
user = request.object;
console.log(" I am inside if else");
var Customer = Parse.Object.extend("Customer");
var cus = new Customer();
cus.set("name2" , "albert")
var relation = cus.relation("userId");
relation.add(user);
cus.save(); // Customer object should get saved here
cus.save(null, {
success: function(cus) {
// Execute any logic that should take place after the object is saved.
console.log("I am working")
alert('New object created with objectId: ' + cus.objectId);
},
error: function(error) {
// handleParseError(error);
console.log(error)
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
}
});
}
});
Log when I run this:
after_save triggered for _User for user qu808uKOgt:
Input: {"object":{"createdAt":"2015-10-11T18:36:07.661Z","objectId":"qu808uKOgt","phone":"5678956475","role_name":"customer","updatedAt":"2015-10-11T18:36:07.661Z","username":"newuser16"}}
Result: Success
I am inside if else
{"name2":"apple","userId":{"__op":"AddRelation","objects": [{"__type":"Pointer","className":"_User","objectId":"qu808uKOgt"}]}}
I fixed this bug by creating a new cloud function, which will be called immediately after the user sign's up.
Parse.Cloud.define('functionName', function(request, response){
var currentUser = Parse.User.current();
var role_name = currentUser.get("role_name");
if (role_name == "customer"){
// Do something
}
else if (role_name == "service_provider"){
// Do something else
}
)};

Update indexedDB

Hi I am trying to update records indexdb. I want to implement a generic method that allows me to upgrade to any field.
To do this I have a function that returns me the record I need.
function getObjectStoreClienteDB(clave,valor){
//Ahora recogeremos los datos de nuestro almacén "Productos"
var transaction = db.transaction(["customers"], "readwrite");
var objectStore = transaction.objectStore("customers");
var index = objectStore.index(clave);
var singleKeyRange = IDBKeyRange.only(valor);
// To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()
return index.openCursor(singleKeyRange);
}
And another that updates the returned record
function updateClienteDB(clave,valor,newvalor){
console.log("updateClienteDB ... clave: "+clave+" valor: "+valor+" newvalor: "+newvalor);
var objectStore = db.transaction(["customers"], "readwrite").objectStore("customers");
request = getObjectStoreClienteDB("name",valor);
request.onsuccess = function(event) {
// Get the old value that we want to update
var data = request.result;
// update the value(s) in the object that you want to change
if(clave=="name")
data.name = newvalor;
else if(clave=="email")
data.email = newvalor;
else if(clave=="matricula")
data.matricula = newvalor;
else if(clave=="telefono")
data.telefono = newvalor;
// Put this updated object back into the database.
var requestUpdate = objectStore.put(data);
requestUpdate.onerror = function(event) {
console.log("addCliente ..."+name+" "+email +" "+ event.target.errorCode);
};
requestUpdate.onsuccess = function(event) {
console.log("All done!");
};
};
}
In the line:
var requestUpdate = objectStore.put(data);
error:
Uncaught TransactionInactiveError: Failed to execute 'put' on 'IDBObjectStore': The transaction has finished.
Try using the same readwrite transaction. It looks like you are calling db.transaction(...) in two places. You are then trying to update an object store linked to a different transaction in the context of a different transaction. The result is that one of the transactions completes (its lifetime ends), probably because it times out, because it does not detect any registered requests. The objectStore variable lives within the lifetime of the transaction that completes early, so you get a transaction finished error.
This is trivial to fix. You simply need to register a new request (the put request) on the same transaction before its lifetime ends. To do this, you can either (a) inline the statement request = getObjectStoreClienteDB("name",valor); so that it is attached to the same transaction instance, or (b) store the transaction instance in a separate variable and reference that in both calls.
For example, the following code is a modification of yours that uses a single transaction:
// this function was changed, it now takes an active transaction as its first argument.
function getObjectStoreClienteDB(transaction, clave,valor){
//Ahora recogeremos los datos de nuestro almacén "Productos"
// this was changed. instead of creating a new transaction we just reference the
// transaction instance passed to this function
var objectStore = transaction.objectStore("customers");
var index = objectStore.index(clave);
var singleKeyRange = IDBKeyRange.only(valor);
// To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()
return index.openCursor(singleKeyRange);
}
function updateClienteDB(clave,valor,newvalor){
console.log("updateClienteDB ... clave: "+clave+" valor: "+valor+" newvalor: "+newvalor);
// this line was added. we create the transaction here, once
var transaction = db.transaction(["customers"], "readwrite");
// this line was changed, we simply reference the transaction instance here instead of
// creating a second transaction
var objectStore = transaction.objectStore("customers");
// this line was changed, we pass in the one active transaction instance to the function
// now instead of having the function create its own transaction
request = getObjectStoreClienteDB(transaction, "name",valor);
request.onsuccess = function(event) {
// Get the old value that we want to update
var data = request.result;
// update the value(s) in the object that you want to change
if(clave=="name")
data.name = newvalor;
else if(clave=="email")
data.email = newvalor;
else if(clave=="matricula")
data.matricula = newvalor;
else if(clave=="telefono")
data.telefono = newvalor;
// Put this updated object back into the database.
// this line now works. objectStore is attached to our 1 transaction that is still 'alive'
// because it gets registered 'in time' (before transaction finishes due to timeout due
// to no additional requests registered in allowed time window).
var requestUpdate = objectStore.put(data);
requestUpdate.onerror = function(event) {
console.log("addCliente ..."+name+" "+email +" "+ event.target.errorCode);
};
requestUpdate.onsuccess = function(event) {
console.log("All done!");
};
};
}
And, just to be clear, here is a second example. It re-creates a reference to the object store using the transaction of the caller, instead of cross referencing an object store attached to a different transaction:
function updateClienteDB(clave,valor,newvalor){
console.log("updateClienteDB ... clave: "+clave+" valor: "+valor+" newvalor: "+newvalor);
var objectStore = db.transaction(["customers"], "readwrite").objectStore("customers");
request = getObjectStoreClienteDB("name",valor);
request.onsuccess = function(event) {
// Get the old value that we want to update
var data = request.result;
// update the value(s) in the object that you want to change
if(clave=="name")
data.name = newvalor;
else if(clave=="email")
data.email = newvalor;
else if(clave=="matricula")
data.matricula = newvalor;
else if(clave=="telefono")
data.telefono = newvalor;
// Put this updated object back into the database.
// the following line is changed so that it works.
//var requestUpdate = objectStore.put(data);
var theOtherTransactionThatIsStillAlive = event.transaction;
var objectStoreFromValidTransaction = theOtherTransactionThatIsStillAlive.objectStore('customers');
var requestUpdate = objectStoreFromValidTransaction.put(data);
requestUpdate.onerror = function(event) {
console.log("addCliente ..."+name+" "+email +" "+ event.target.errorCode);
};
requestUpdate.onsuccess = function(event) {
console.log("All done!");
};
};
}

Error "Data provided to an operation does not meet requirements" when adding objects in indexedDB

When i try to add the object to the objectStore with .add, the console shows this error:
DataError: Data provided to an operation does not meet requirements. If someone can tell where this error came from it will really help me. This is the code:
var request = objStore.add({tarea: todo, clase: "pendiente"});
var db;
function create_to_do(){
var todo = document.querySelector('#the-do').value;
var transaction = db.transaction("to_do", "readwrite");
transaction.oncomplete = function(eve){
console.log("all done¡")
}
transaction.onerror= function(eve){
console.log("something went wrong: "+ eve.target.errorCode);
};
var objStore = transaction.objectStore("to_do");
var request = objStore.add({tarea: todo, clase: "pendiente"});
request.onsuccess = function(eve){
console.log("all done¡");
console.log(eve.target.result);
};
}
function indexDB(){
var request = indexedDB.open('todos', 1);
request.onsuccess = function (evt) {
db = this.result;
console.log("Database Opened");
};
request.onerror = function (evt){
console.log("OpenDB error: " + evt.target.errorCode);
};
request.onupgradeneeded = function(evt){
store = evt.currentTarget.result.createObjectStore("to_do",
{keyPath: 'id', autoIncrement: true});
store.createIndex('clase', 'clase', {unique: false});
console.log("index created");
};
}
try keyPath: 'keyPath' or autoIncrement: false once you provide a "primary key" you have to set autoIncrement to false see it here
You are trying to save a DOM object. Depending on what is in there, you will or won't be able to save your data. Try leaving the tarea property out of the object and save that. And let me know what is in the tarrea property
var todo = document.querySelector('#the-do').value;
var request = objStore.add({tarea: todo, clase: "pendiente"});
It's a simple typo. The auto-increment option to the createObjectStore() method must be spelled autoIncrement (with capital I), not autoincrement.
What happens is that your object store is created without a key generator, so when adding an object it's looking for an id property as per your key path. Because the property doesn't exist you get the DataError.

Categories