Local Storage using Dexie not staying persistent - javascript

I am using Dexie to access IndexedDB on a flash card maker project. I can manipulate the database as expected, and it stays in the database if I close and reopen the browser, but often when I open up the project after not working on it for a few days, the stored data I put into the database isn't there any longer.
I did some research and discovered that I need to make the database persistent, but I can't figure out how to do that.
I have pretty much copied the recommended code from the Dexie Storage Manager page into the onLoad function for the main page, index.js. Here is the relevant code:
//When the page loads, display the decks in ul on the webpage.
window.addEventListener('load', onLoad);
async function onLoad() {
//Check how much data is available.
showEstimatedQuota();
//Make sure the storage is persistent.
isStoragePersisted().then(async isPersisted => {
if (isPersisted) {
console.log(":) Storage is successfully persisted.");
} else {
console.log(":( Storage is not persisted.");
console.log("Trying to persist..:");
if (await persist()) {
console.log(":) We successfully turned the storage to be persisted.");
} else {
console.log(":( Failed to make storage persisted");
}
}
});
}
The above onLoad function references three functions I have saved on dexie-setup.js:
//This function makes the storage persistent.
//(Copied from https://dexie.org/docs/StorageManager)
async function persist() {
return await navigator.storage && navigator.storage.persist &&
navigator.storage.persist();
}
//This function checks if the storage is persistent.
//(Copied from https://dexie.org/docs/StorageManager)
async function isStoragePersisted() {
return await navigator.storage && navigator.storage.persisted &&
navigator.storage.persisted();
}
//This function logs to console how much data is available.
//(Copied from https://dexie.org/docs/StorageManager)
async function showEstimatedQuota() {
if (navigator.storage && navigator.storage.estimate) {
const estimation = await navigator.storage.estimate();
console.log(`Quota: ${estimation.quota}`);
console.log(`Usage: ${estimation.usage}`);
} else {
console.error("StorageManager not found");
}
}
My console logs:
dexie-setup.js:56 Quota: 6358499328
dexie-setup.js:57 Usage: 25370
index.js:30 :( Storage is not persisted.
index.js:31 Trying to
persist..:
dexie-setup.js:84 Done checking dexie.
index.js:33 :) We successfully turned the storage to be persisted.
However, if I refresh the page, I get the same thing logged on my console: the database is still set to not persistent.
The showEstimatedQuota function checks the data storage and confirms that the DataStorage API is functioning, so I don't think that's the problem. (I'm only storing small objects with text in them, so I don't expect to exceed the storage limit, anyway.)
So far, the project is entirely local on my chromebook, and I am viewing it on a Chrome browser.
Please let me know how to make my database persistent. I'm pretty new to this (this is my first question on stackoverflow!), so hopefully it's an easy problem to solve! Thanks in advance.

citing the documentation of Dexie: "Even though IndexedDB is a fully functional client-side database for the web, it is not a persistent storage by default. IndexedDB without StorageManager is just a “best-effort” database that can be erased in situations of low disk space on a device. The browser may delete your database without notifying the user in case it needs to free up space for other website’s data that was used more recently than yours."
So, you can't make the database persistent. Just make a “best-effort”.
This links can be of help:
https://web.dev/persistent-storage/
Chrome.Storage.Local Persistence
I hope it will be of help to you.

The only way I have found is that if the user bookmarks the site then it enables persistent storage using the persist function:
//This function makes the storage persistent.
//(Copied from https://dexie.org/docs/StorageManager)
async function persist() {
return await navigator.storage && navigator.storage.persist &&
navigator.storage.persist();
}
So you may prompt the user to bookmark your site when it loads.

Related

Clean IndexedDB when tab is closing

I need to keep some data in indexedDB instead on sessionStorage as amount of data is more than 5 MB.
I'm confused about cleanup strategy as in case of page reload or navigation to the other page I need this data to be kept, but if user closes browser tab I'd like to remove it to save place.
How can I do that? Need it to be working at least in Chrome.
You can store an indicator in the session storage, then delete the database if that value does not exist.
(async() =>
{
if (!sessionStorage.getItem('just-a-placeholder'))
{
indexedDB.deleteDatabase('temp');
sessionStorage.setItem('just-a-placeholder', true);
}
const databases = await indexedDB.databases();
console.log(databases.find(db => db.name === 'temp') !== undefined)
await indexedDB.open('temp');
})();
Sadly StackOverflow does not run snippets in a way I could show this here but here is a JSFiddle to show it in action.

Storing DeviceOrientationEvent and DeviceMotionEvent permissions across pages

I've got a nice DeviceMotionEvent request all working for Safari (or other browsers that require the permission), something along these lines:
// on click of a button
DeviceMotionEvent.requestPermission()
.then(response => {
if (response == 'granted') {
// do my thing
}
})
.catch(function(error) {
console.log(error);
// do my other thing
});
And thats working great. But when a user goes to a new page, they have to request the permission again. Obviously I'm calling 'requestPermission' again, so of course they would do.
How do I find out if permission has already been granted? Or is permission granted on a page by page basis (rather than session / site basis)?
I could store the response in localstorage or something, but would prefer something along the lines of:
DeviceMotionEvent.permissionStatus
Or something?
I think you only option is to build a single page application and use the history.pushState() to update the location in the browser, when you wish to ‘change pages’.
Edited:
You can use the Web Storage API with the following two mechanisms:
sessionStorage
localStorage
As the names imply, these two interfaces are ideal for session-based data or if you want to persist state even after the connection is closed.
You should be able to check whether permissions have been granted using the devicemotion eventListener. Baring in mind you have to push a button or similar to run DeviceMotionEvent.requestPermission()
eg.
let hasOrientationControls = false;
window.addEventListener("devicemotion", () => {
hasOrientationControls = true;
});
// then when the button is pressed we can request permissions if we need
onButtonPressed () => {
if (hasOrientationControls) return;
else DeviceMotionEvent.requestPermission();
}
I've also used this
isVRReady = window.DeviceOrientationEvent && "ontouchstart" in window;

JavaScript: Like-Counter with Memory

Complete - Edited Once
I am looking to create a Like Counter with persistent Memory!
Right now, my project is stored on a USB-Drive and I'm not thinking of uploading my semi-finished site to the Internet just yet. I'm carrying it around, plugging and working.
A feature of the site, is a Heart Counter and Like Counter, respective with their symbolic icons.
I have a little sideline JavaScript file that has a dozen functions to handle the click-events and such - such as the Number Count of the counters.
But, as the values of the counters are auto-assigned to Temporary Memory - if you were to reload the page - the counter number would reset to it's default, Zero. A huge headache...
Reading from .txt
I thought of using the experimental ReadFile() object to handle the problem - but I soon found that it needed a user-put file to operate (from my examinations).
Here's my attempt:
if (heartCount || likeCount >= 1) {
var reader = new FileReader();
var readerResults = reader.readAsText(heartsAndLikes.txt);
//return readerResults
alert(readerResults);
}
When loaded, the page runs through standard operations, except for the above.
This, in my opinion, would have been the ideal solution...
Reading from Cookies
Cookies now don't seem like an option as it resides on a per-computer basis.
They are stored on the computer's SSD, not in the JavaScript File... sad...
HTML5 Web Storage
Using the new Web Storage will be of big help, probably. But again, it is on a per-computer basis, no matter how beautiful the system is...
localStorage.heartCount = 0 //Originally...
function heartButtonClicked() {
if (localStorage.heartCount) {
localStorage.heartCount = Number(localStorage.heartCount) + 1
}
document.getElementById('heartCountDisplay').innerHTML = localStorage.heartCount
} //Function is tied to the heartCountButton directly via the 'onclick' method
However, I am questioning whether web storage can be carried over on a USB-Drive...
Summarised ideas
Currently, I am looking to Reading and Editing the files, as it's most ideal to my situation. But...
Which would you use? Would you introduce a new method of things?
Please, tell me about it! :)
if (typeof(Storage) !== "undefined") { //make sure local storage is available
if (!localStorage.heartCount) { //if heartCount is not set then set it to zero
localStorage.heartCount = 0;
}
} else {
alert('Local storage is not available');
}
function heartButtonClicked() {
if (localStorage.heartCount) { //if heartCount exists then increment it by one
localStorage.heartCount++;
}
//display the result
document.getElementById('heartCountDisplay').innerHTML = localStorage.heartCount
}
This will only work on a per computer basis and will not persist on your thumb drive. The only way I can think of to persist the data on your drive is to manually download a JSON or text file.

PouchDB: Clear localDB when it is safe on remoteDB

Context
I use PouchDB and have a localDB using indexedDb. I continuously replicating this local DB to a remote DB (CouchDB) with this function:
function replLocalToRemote() {
this.meta.localDB.replicate.to(this.meta.remoteDB, {
// Live: replication occurs as the changes are detected
live: true,
retry: true,
}).on('paused', function (info) {
console.log('paused', info);
// replication was paused, usually because of a lost connection
}).on('change', function (change) {
console.log('change', change);
// yo, something changed!
}).on('active', function (info) {
console.log('active', info);
// replication was resumed
}).on('error', function (err) {
alert('replication failed. Retry... ', err);
// totally unhandled error (shouldn't happen)
});
}
It is working well but problems appear when there is too much data on the device. Especially on IOS where Safari constantly open pop-up windows to ask for more data storage (beginning at 5Mo).
Question
So I would like to clean the localDB as I replicate it to the remoteDB. For instance delete a document on local as soon as it is on remote and continue replication even if there is more data on remote than on local.
Is this possible?
Deleting the local document would cause you problems, as the deletion would be replicated to the remote database so that you lose the document altogether.
Have you seen the "auto-compaction" feature in PouchDb? That minimises the size of the local database by removing any "non-leaf" revision documents (previous versions).
You can enable this feature like this:
var db = new PouchDB('mydb', {auto_compaction: true});
More information about this is on the PouchDb page.
What you can try is create a new local db every now and then (e.g. every day), and starting a new replication from there. Keep the old dbs as long as they still replicate, and remove them as soon as they are fully replicated.
In order not to lose any data, you should take extra care that all data has been replicated to the server before deleting the db.

How to know if user has completed all tasks?

I am making kind of an app using only HTML, JavaScript and CSS, with several little games for kids (like puzzles, order words, draw and paint...). I have the index page with links to the pages of each game, and once the game is over, it redirects directly to the index page, all in the same browser tab.
What I would like to know is if there is some way of knowing when the player has completed one game, so after that, the game would be locked, and once the player has completed all games, it would unlock a special prize or someting.
I have tried with local storage, but the problem is that once I've played one game, it will stay locked, because the local storage keeps in memory that I have played it, even if I close the browser. Is there any way of using local storage with it "losing its memory" once you close the browser? Or is there a more efficient way than local storage?
Any help would be much appreciated!
A good read for you : http://www.smashingmagazine.com/2010/10/11/local-storage-and-how-to-use-it/
Here is what you can do with regards to local storage :
When the page is loaded set up your local storage and set all games to incomplete
Create a store() and check() function to help you out and make things easier
function store(game, status){
localStorage.setItem(game, status);
}
function check(game){
return localStorage.getItem(game);
}
window.onload = function() {
store("puzzle1", false);
store("puzzle2", false);
store("puzzle3", false);
}
As the user completes the game you can alter the data inside the storage :
someEvent() {
store("puzzle1", true);
}
and then at the end of the game, or on your games starting page just run some checks :
//if puzzle1 is true
if(check("puzzle1")) {
//do Stuff
}
I believe that should work for you.
You can use the SessionStorage. By definition "it persists in the same tab", meaning that once the page is closed, the storage is lost.
Reference: https://code.google.com/p/sessionstorage/
as an example you can follow this i hope it helps you...
<!DOCTYPE html>
<html>
<body>
<div id="result"></div>
<script>
// Check browser support
if (typeof(Storage) != "undefined") {
// Store
localStorage.setItem("lastname", "Smith");
// Retrieve
document.getElementById("result").innerHTML = localStorage.getItem("lastname");
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support Web Storage...";
}
</script>
</body>
</html>
try to google sessionstorage for html, there are many examples..good luck!!

Categories

Resources