indexeddb Invalid state error by call-stack? - javascript

Again, i got some question on indexeddb. I´m getting a
InvalidStateError: A Mutation operation was attempted on a database
that did not allow mutations.
and also an
AbortError
Here is my code:
DB_LINK.prototype.pushStoreNumeric = function ()
{
// Saving Values
var _temp = 0;
var _version = this.link.version;
var _name = this.link.name;
var that = this;
var _objectStoreNames = this.link.objectStoreNames;
// Close DB
this.link.close();
this.state = 4;
// Reopen Database
this.req = indexedDB.open(_name,_version+1); // Abort error here
this.req.onupgradeneeded = function () {
that.state = 1;
// Get Number of object stores
_temp = _objectStoreNames.length;
if(_temp != 0)
{
// Already object stores: read highest value
_temp = parseInt(_objectStoreNames[_objectStoreNames.length - 1]);
}
that.link.createObjectStore(_temp); // InvalidStateError here
};
I have marked per comment where the errors occur.
The InvalidStateError occures first, the AbortError follows.
I am calling this function inside another onsuccess function of the same database. Might this be the problem?

What is this.link? That's probably the problem. You need to be doing createObjectStore on the database instance created by the indexedDB.open request. So either this.req.result.createObjectStore or (if you change to this.req.onupgradeneeded = function (e) {) you could use e.target.result.createObjectStore.
More generally, I can't really comment on what your code is supposed to be doing because I can only see a snippet, but it looks really weird how you are incrementing the version every time this is called. Probably you don't actually want to be doing that. You might want to read a bit more documentation.

Related

Failed to execute 'put' on 'IDBObjectStore': The transaction has finished

I am trying to update an entry in my simple to do app with indexedDB, however I am getting Failed to execute 'put' on 'IDBObjectStore': The transaction has finished.
I can't seem to figure out why it won't finish the transaction, I tried the debugger and it stops at this line: var updateNameRequest = tasksStore.put( requestForItem.result.name, Number(requestForItem.result.id)) Please see the snippet I included below. For additional context creating, reading, and deleting work just fine it's just updating data that I'm having trouble with
I also tried to implement the openCursor technique which I got from Mozilla which I commented out since it also doesn't work (I get the same behavior) Check out my repo I know it's still very messy :(
const request = window.indexedDB.open("toDoList", 2);
var db;
request.onsuccess = function (event) {
console.log("check out some data about our opened db: ", request.result);
db = event.target.result; // result of opening the indexedDB instance "toDoList"
getTasks(); //just a function to retrieve data
};
$(document).on("click", ".editBtn", function () {
var transaction = db.transaction("tasks", "readwrite");
var tasksStore = transaction.objectStore("tasks");
console.log(tasksStore);
let taskId = $(this).attr("idNo");
var requestForItem = tasksStore.get(Number(taskId));
requestForItem.onsuccess = function () {
// console.log(requestForItem.result)
var oldData = requestForItem.result;
// prepopulate the input
$(".editInput").val(requestForItem.result.name);
$(".saveBtn").click(function () {
requestForItem.result.name = $(".editInput").val().trim()
console.log( requestForItem.result)
var updateNameRequest = tasksStore.put( requestForItem.result.name, Number(requestForItem.result.id))
console.log("-------------", updateNameRequest.transaction) // doesn't get to this line
updateNameRequest.onerror = function() {
console.log("something went wrong")
console.log(updateNameRequest.error)
};
updateNameRequest.onsuccess = function() {
console.log("here")
$(".editInput").val("")
getTasks();
};
});
};
Indexed DB transactions auto-commit when all requests have been completed and no further requests were made before control returns to the event loop. Put another way - you can make new requests in the success or error callback from a previous request, but not in other asynchronous callbacks such as event handlers.
You need to start a new transaction within the click handler, because any previous transaction will have autocommitted.

Getting this error Uncaught RangeError: Maximum call stack size exceeded

I am getting this error while uploading the CSV files in my website.
Screenshot attached below.
I can see my data of csv file while debugging but it is stopping me to proceed further but i am not able to get this error, I have searched that on google to but they are not relevant to this.
I am using the library
https://d3js.org/d3-dsv.v1.min.js
The code I am trying to upload file is below.
function file(event){
var uploadFileEl = document.getElementById('upload');
if(uploadFileEl.files.length > 0){
var reader = new FileReader();
reader.onload = function(e) {
fileProcess(reader.result.split(/\[\r\n\]+/));
}
reader.readAsText(uploadFileEl.files\[0\]);
}
}
function fileProcess(data) {
var lines = data;
//Set up the data arrays
var time = \[\];
var data1 = \[\];
var data2 = \[\];
var data3 = \[\];
var headings = lines\[0\].split(','); // Splice up the first row to get the headings
var headerCheckbox = document.getElementById('includeHeader');
if(headerCheckbox.checked == true){
for (var j=1; j<lines.length; j++) {
var values = lines\[j\].split(','); // Split up the comma seperated values
// We read the key,1st, 2nd and 3rd rows
time.push(values\[0\]); // Read in as string
// Recommended to read in as float, since we'll be doing some operations on this later.
if (values\[0\] =="" || values\[0\] == null )
{
delete values\[0\];
delete values\[1\];
delete values\[2\];
delete values\[3\];
}
else{
data1.push(parseFloat(values\[1\]));
data2.push(parseFloat(values\[2\]));
data3.push(parseFloat(values\[3\]));
}
}
The error I am getting is on this line
fileProcess(reader.result.split(/[\r\n]+/));
What could be the reason for this.
That error means that you are filling the call stack.
If you call a function that returns a function recursively and doesn't have a stop condition or it never fulfils it's stop condition that error will be throwed.
It appears that fileProcess(reader.result.split(/[\r\n]+/)) it's being called recursively and it's filling the call stack.
Don't know exactly where, as I don't see any recursive calls in the code you posted, so I can't help you farer, but I hope this can shed light into your problem.
P.S: If you think there's some relevant extra code that you didn't post and edit your question leave me a comment and I'll update my answer aswell.

Not able to retrieve object properties when looping through objects in indexedDB

I am not able to retrieve properties when looping through objects stored in indexedDB. When i attempt to get objects trough tasksStore.get(i);, i get the error Cannot read property 'property' of undefined at IDBRequest.getTasks.onsuccess, however, if I change it to tasksStore.get(1);, it works fine, and gets object with id=1 x index's length.
I've tried checking the typeof of both ways, and they both return number.
//success handler on connection
request.onsuccess = function(e) {
db = request.result;
//define store index
tasksStore = tasksTx.objectStore("tasksStore");
//error handler on result of the request
db.onerror = function(e) {
console.log("ERROR " + e.target.errorCode);
}
//variable for counting objects in the index
let amountOfTasks = tasksIndex.count();
//error handler
amountOfTasks.onerror = function() {
console.log("There was an error finding the amount of tasks")
}
//success handler
amountOfTasks.onsuccess = function() {
for (var i = 1; i < amountOfTasks.result; i++) {
let getTasks = tasksStore.get(i);
let getTasksElementContainer = document.getElementById("list-tasks");
let createTasksList = document.createElement("li");
createTasksList.id = "task-" + i;
getTasks.onerror = function() {
console.log("There was an error looping through the tasks")
}
getTasks.onsuccess = function() {
console.log(getTasks.result.title); //getTasks.result works, getTasks.result.title does not.
getTasksElementContainer.appendChild(createTasksList);
//JSON stringify to return object in string format, and not [Object object]
createTasksList.innerHTML = JSON.stringify(getTasks.result.title);
}
}
}
}
When you call IDBObjectStore.get with a key that doesn't exist in your database, the resulting value is undefined. That likely explains why sometimes getTasks.result is undefined.
If you're still having trouble, you'd likely be well served by making a self-contained reproducible example. You'll probably find your own bug in the process of doing that. If not, it's easier to get more specific help on Stack Overflow if you have some code that other people can run to directly observe the problem (so including database creation and inserting data).

Firebase functions - Counting children and updating an entry

I have been trying to use Firebase Functions to write a simple method, but I am unfamiliar with JS.
Below is the structure of my Realtime Database
-spots
---is_hidden: false
---likes
------like_id_1: true
---dislikes
------dislike_id_1: true
I am trying to write a simple method that does the following: Whenever an entry is added to dislikes, count the likes and the dislikes.
If the number of dislikes is larger than the number of ( likes + 5 ),
change the value of is_hidden to true
This is my attempt to solving the problem
exports.checkHiddenStatus = functions.database.ref('/spots/{spotid}').onWrite(
(change, context) => {
const collectionRef = change.after.ref;
const isHiddenRef = collectionRef.child('is_hidden');
const likesRef = collectionRef.child('likes');
const dislikesRef = collectionRef.child('dislikes');
if(isHiddenRef.before.val()) return;
let likeCount = likesRef.numChildren();
let dislikeCount = dislikesRef.numChildren();
let isHidden = false;
if( dislikeCount >= (likeCount + 5))
isHidden = true;
if(!isHidden) return;
// Return the promise from countRef.transaction() so our function
// waits for this async event to complete before it exits.
return isHiddenRef.transaction((current) => {
return isHidden;
}).then(() => {
return console.log('Counter updated.');
});
});
Sadly, because I have no experience with JS I keep getting stuck with error messages I don't understand. The most recent being
TypeError: Cannot read property 'val' of undefined
at exports.checkHiddenStatus.functions.database.ref.onWrite (/user_code/index.js:28:28)
Can somebody please help me write this function? Thank you!
It looks like you're trying to treat a database Reference object like a Change object. Change has before and after properties, but a reference does not.
If you have a database reference object, and you want the value of the database at that location, you need to query it with its once() method.
Read more about reading and writing data using the Admin SDK.

Firebase database change not working

I have the following code I'm trying to make a simple hit counter with. However, it doesn't work when I run it locally. When I start newHits as blank, it throws the error: Uncaught Error: Reference.set failed: First argument contains undefined in property 'hits.number'.
When I start it at 1, it just doesn't change the value of the hits in the database. Any help is appreciated: I'm new to programming. Thanks so much!
$(document).ready(function(){
var database = firebase.database();
var hits;
var newHits = 1;
var hitsRef = firebase.database().ref('hits');
hitsRef.once('value', function(snapshot){
console.log("hitsRef.once called");
hits = snapshot.val().number;
console.log("hits: "+hits);
newHits = hits+1;
console.log(newHits);
});
hitsRef.set({
number: newHits
});
});
the simple way to do that by using transaction see here
$(document).ready(function(){
var database = firebase.database();
var hitsRef = firebase.database().ref('hits/number');
hitsRef.transaction(function(hits){
console.log("hitsRef.once called");
hits++;
return hits
});
}
This is due to async nature of once(). According to your code, both once() and set() are called for the same value of i at once.
If you want to test it, place your set() within a setTimeout() like,
setTimeout(function(){
hitsRef.set({
number: newHits
});
}, 2000);
You will see that your problem is solved but this is not the correct way.Try this instead,
var i = 1;
hitsRef.once('value', function(snapshot){
console.log("hitsRef.once called");
hits = snapshot.val().number;
console.log("hits: "+hits);
newHits = hits+1;
console.log(newHits);
})
.then( function() { // change starts here
hitsRef.set({
number: newHits
});
});
Your set() method will only be called when once() is done retrieving hits. This works because once() returns a promise and it is thenable.
Read these then() in javascript and promises.

Categories