static void

LocalStorage and IndexedDB

Written September 2012- specs and browser support will change! Updated 2024.

Local Storage

localStorage["key"] = 29; //or localStorage.setItem(key, value);
//always coerce types
var find = parseInt(localStorage["key"], 10); //or localStorage.getItem(key)
var size = localStorage.length;

IndexedDb

Open/create the database

async function createOrRecreateDatabase() {
    // Open a connection to the database
    const request = indexedDB.open("CountryDb", 1);

    // If the database does not exist - or needs updating
    request.onupgradeneeded = event => {
        const db = event.target.result;

        // If the Countries object store already exists, delete it
        if (db.objectStoreNames.contains("Countries")) {
            db.deleteObjectStore("Countries");
        }

        // Create the Countries object store with a key path of 'id' and autoIncrement set to true
        const countryStore = db.createObjectStore("Countries", { keyPath"id"autoIncrementtrue });

        // Create an index on the 'Name' property
        countryStore.createIndex("by_name""LowerCaseName", { uniquefalse });

        // Add initial data
        // for case insensitive search, add a lowercase property to the object
        const countries = [
            { Name"Australia"ShortName"AU"LowerCaseName"Australia".toLowerCase() },
            { Name"Belgium"ShortName"BE"LowerCaseName"Belgium".toLowerCase() },
            { Name"Brazil"ShortName"BR"LowerCaseName"Brazil".toLowerCase() },
            { Name"Canada"ShortName"CA"LowerCaseName"Canada".toLowerCase() },
            { Name"China"ShortName"CN"LowerCaseName"China".toLowerCase() },
           // Add more countries as needed...
        ];

        countries.forEach(country => {
            countryStore.add(country);
        });
    };

    request.onerror = event => {
        console.error("Database error: "event.target.error);
    };

    request.onsuccess = event => {
        console.log("Database created successfully");
    };
}

ObjectStore- saving

async function updateCountryName(idnewName) {
    return new Promise((resolvereject) => {
        const request = indexedDB.open("CountryDb", 1);

        request.onerror = event => {
            console.error("Database error: "event.target.error);
            reject("Failed to open DB");
        };

        request.onsuccess = event => {
            const db = event.target.result;
            const transaction = db.transaction("Countries""readwrite");
            const store = transaction.objectStore("Countries");

            const getRequest = store.get(id);
            getRequest.onerror = event => {
                console.error("Error fetching country: "event.target.error);
                reject("Failed to fetch country");
            };

            getRequest.onsuccess = event => {
                const data = event.target.result;
                data.Name = newName// Update the name
                data.LowerCaseName = newName.toLowerCase();

                const putRequest = store.put(data);
                putRequest.onerror = event => {
                    console.error("Error updating country: "event.target.error);
                    reject("Failed to update country");
                };

                putRequest.onsuccess = () => {
                    resolve("Country updated successfully");
                };
            };
        };
    });
}

ObjectStore - reading

.get(key)

async function fetchAllCountries() {
    return new Promise((resolvereject) => {
        const request = indexedDB.open("CountryDb", 1);

        request.onerror = event => {
            console.error("Database error: "event.target.error);
            reject("Failed to open DB");
        };

        request.onsuccess = event => {
            const db = event.target.result;
            const transaction = db.transaction("Countries""readonly");
            const store = transaction.objectStore("Countries");
            const getAllRequest = store.getAll();

            getAllRequest.onerror = event => {
                console.error("Error fetching countries: "event.target.error);
                reject("Failed to fetch countries");
            };

            getAllRequest.onsuccess = event => {
                resolve(event.target.result);
            };
        };
    });
}

.openCursor(range) often via .index(name)

async function searchCountriesByNamePrefix(namePrefix) {
    return new Promise((resolvereject) => {
        const request = indexedDB.open("CountryDb", 1);

        request.onerror = event => {
            console.error("Database error: "event.target.error);
            reject("Failed to open DB");
        };

        request.onsuccess = event => {
            const db = event.target.result;
            const transaction = db.transaction("Countries""readonly");
            const store = transaction.objectStore("Countries");
            const index = store.index("by_name");
            // Convert the prefix to lowercase for case-insensitive search
            const lowercasedPrefix = namePrefix.toLowerCase();
            const range = IDBKeyRange.bound(lowercasedPrefixlowercasedPrefix + '\uffff');
            const cursorRequest = index.openCursor(range);
            const results = [];
            let count = 0; // Counter for the number of records

            cursorRequest.onerror = event => {
                console.error("Error searching countries: "event.target.error);
                reject("Failed to search countries");
            };

            cursorRequest.onsuccess = event => {
                const cursor = event.target.result;
                if (cursor && count < 100) {
                    if (cursor.value.Name.toLowerCase().startsWith(lowercasedPrefix)) {
                        results.push(cursor.value);
                    }
                    cursor.continue();
                } else {
                    // No more results
                    resolve(results);
                }
            };
        };
    });
}

Demo

Using dbOperations.js (all local)

Add a New Country

Search Countries

How much storage?

navigator.storage.estimate().then(function(estimate) { })

Usage

Quota

function formatBytes(bytesdecimals = 2) {
    if (bytes === 0) return '0';
    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes''KB''MB''GB''TB''PB''EB''ZB''YB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(ki)).toFixed(dm)) + ' ' + sizes[i];
}