TL;DR: collection.modify() works with a few records, but fails when trying to modify more than 10 records at once. Why?
I have some code that displays and interacts with a database using Javascript, HTML, and a Dexie wrapper over IndexedDB. Here's the problem: I can only modify a few records at a time. If I try more than ~8-10 records, modify() fails with no error.
Here's how I call the database and draw the query tables:
//Every time the page refreshes, the db is open and draws tables
$document.ready(function(){
//Open database
db=new Dexie("peopleManager");
db.version(1).stores({
people: "id++, name, location"
});
//Call functions that draw query tables
showDallas();
showNewYork();
});
//Draws an HTML table of people who work in Dallas
function showDallas(){
var output = '';
db.people
.where("location")
.equals("Dallas")
.each
(function(people){
output += "<tr align='center'>";
output += "<td>"+people.id+"</td>";
output += "<td>"+people.name+"</td>";
output += "</tr>";
$('#dallas').html(output);
});
}
//Draws an HTML table of people who work in NY
function showNewYork(){
var output = '';
db.people
.where("location")
.equals("New York")
.each
(function(people){
output += "<tr align='center'>";
output += "<td>"+people.id+"</td>";
output += "<td>"+people.name+"</td>";
output += "</tr>";
$('#newYork').html(output);
});
}
Here's the function that keeps failing. It gets fired by a click on an HTML button:
//Move all to New York
function moveToNewYork(){
db.transaction('rw', db.people, function(){
db.people.where("location").equals("Dallas").modify({location: "New York"});
}).then(function(){
window.location.reload();
}).catch(Dexie.ModifyError, function(e){
console.error(e.failures.length + "failed to hire modify");
throw e;
});
}
HTML button:
<form role = "form" onSubmit = "moveToNewYork()">
<button type="submit" class="btn btn-primary">Move All</button></form>
I can modify less than 10 records. More than ten and the page refreshes with no change to the db and no error recorded. Following the documentation but haven't seen any examples where modify() would need to change 10+ records. I haven't found anything that shows a modify() transaction fails after a certain number of records.
Anyone see what I'm doing wrong, or how I can troubleshoot this further?
Note that the actual code is long with about 20 other read-only operations going on.
Update: Here's a full JSFiddle showing the error. With these (very small) records, I can get to 12-15 before modify() starts to fail. Weirdly, clicking again a few times randomly gets modify() to work maybe 1 out of 8 times? I'm totally stumped.
I didn't manage to repro this until I filled the DB with a thousand records. After that, the page started reloading prematurely, before the items were stored.
The error I got on the JSFiddle isn't exactly what you described, there the page just hits me with a 404 after trying to reload, but I think I know what's going on.
The page isn't reloading because of the window.location.reload()
. Instead, the form's submit event bubbles to its default behaviour because it isn't explicitly prevented anywhere. So there's a race-condition; when there's only a small dataset, Dexie manages to finish its work before form reloads the page. When the dataset grows, changes take longer and the form's submit event wins the race.
To fix this, return false
from the onsubmit callback to prevent default submit behaviour.
HTML:
<form role="form" onSubmit="return moveToNewYork()">
^^^^^^ add "return" here
JS:
function moveToNewYork() {
db.transaction('rw', db.people, function() {
db.people.where("location").equals("Dallas").modify({
location: "New York"
});
}).then(function() {
window.location.reload();
}).catch(Dexie.ModifyError, function(e) {
console.error(e.failures.length + "failed to hire modify");
throw e;
});
return false; // add "return false" here
}
And also add the same changes to the other modifying forms & functions.