IndexedDB in HTML​​

IndexedDB is a powerful, low-level API for storing large amounts of structured data within the user’s browser, allowing offline access and efficient data management. Unlike localStorage, which stores data as simple key-value pairs, IndexedDB supports storing complex, structured data such as objects and allows for advanced querying. This makes IndexedDB suitable for more complex web applications, like offline-first apps, data-heavy applications, and applications that need to cache data locally.

In this chapter, we’ll cover everything about IndexedDB from the basics to advanced concepts, including creating a database, performing CRUD operations, and understanding transactions. With IndexedDB, web applications can become faster, more responsive, and work effectively even when the user is offline.

What is IndexedDB?

IndexedDB is a NoSQL database embedded in web browsers, allowing developers to store complex data like objects, arrays, and binary data. Unlike relational databases that use tables and SQL, IndexedDB uses a system of object stores to store records. Each record in an object store is uniquely identified by a key, making it efficient for querying.

Key Features of IndexedDB:

  • Key-Value Storage: Stores data as key-value pairs.
  • Asynchronous API: Most operations are asynchronous, improving performance.
  • Supports Transactions: Helps maintain data integrity by grouping operations.
  • Supports Large Data Storage: Ideal for storing images, media, and structured data.

Setting Up an IndexedDB Database

To create and use an IndexedDB database, you need to open a connection, create an object store (like a table in SQL), and use transactions to interact with the data.

Basic Example: Creating and Opening an IndexedDB Database

				
					let db;
const request = indexedDB.open("MyDatabase", 1); // Open a database called "MyDatabase"

// Handle database upgrades (like creating object stores)
request.onupgradeneeded = function(event) {
    db = event.target.result;
    const objectStore = db.createObjectStore("users", { keyPath: "id", autoIncrement: true });
    objectStore.createIndex("name", "name", { unique: false });
    console.log("Database setup complete.");
};

// Handle successful opening
request.onsuccess = function(event) {
    db = event.target.result;
    console.log("Database opened successfully.");
};

// Handle errors
request.onerror = function(event) {
    console.error("Error opening database:", event.target.errorCode);
};

				
			

Explanation

  1. indexedDB.open("MyDatabase", 1): Opens a database named “MyDatabase” with a version of 1.
  2. onupgradeneeded: Fires if the database is being created for the first time or a new version is requested. This is where you create object stores and indexes.
  3. keyPath: Sets a unique identifier (id) for each entry in the store.

Output: When the code runs, it sets up an IndexedDB database called “MyDatabase” with an object store for “users.”

Adding Data to IndexedDB

After setting up the database, let’s add some data to it. Adding data in IndexedDB is done through transactions.

Example: Adding Data to an Object Store

				
					function addUser(name, age) {
    const transaction = db.transaction(["users"], "readwrite");
    const objectStore = transaction.objectStore("users");

    const request = objectStore.add({ name: name, age: age });

    request.onsuccess = function() {
        console.log("User added:", { name, age });
    };

    request.onerror = function() {
        console.error("Error adding user.");
    };
}

addUser("Alice", 25);
addUser("Bob", 30);

				
			

Explanation

  1. transaction: Initiates a transaction with “readwrite” permission.
  2. objectStore.add: Adds an object to the users store.
  3. The data { name: name, age: age } is added to the store.

Output: When called, addUser("Alice", 25) and addUser("Bob", 30) add two users to the “users” object store.

Reading Data from IndexedDB

Reading data is similar to writing; it also uses transactions, but typically in read-only mode.

Example: Retrieving Data by Key

				
					function getUser(id) {
    const transaction = db.transaction(["users"], "readonly");
    const objectStore = transaction.objectStore("users");

    const request = objectStore.get(id);

    request.onsuccess = function(event) {
        if (request.result) {
            console.log("User found:", request.result);
        } else {
            console.log("User not found.");
        }
    };

    request.onerror = function() {
        console.error("Error retrieving user.");
    };
}

getUser(1); // Assuming "Alice" has id 1

				
			

Explanation

  1. transaction: Creates a read-only transaction.
  2. objectStore.get: Retrieves an object by key (id).

Output: If a user with the given ID exists, it’s logged; otherwise, a message says “User not found.”

Updating Data in IndexedDB

Updating data requires opening a transaction with read-write permissions.

Example: Updating User Data

				
					function updateUser(id, updatedData) {
    const transaction = db.transaction(["users"], "readwrite");
    const objectStore = transaction.objectStore("users");

    const request = objectStore.get(id);

    request.onsuccess = function(event) {
        const data = event.target.result;
        if (data) {
            for (let key in updatedData) {
                data[key] = updatedData[key];
            }
            const updateRequest = objectStore.put(data);
            updateRequest.onsuccess = () => console.log("User updated:", data);
        } else {
            console.log("User not found.");
        }
    };

    request.onerror = () => console.error("Error updating user.");
}

updateUser(1, { age: 26 });

				
			

Explanation

  1. objectStore.get: Retrieves the object to be updated.
  2. objectStore.put: Saves the updated object back into the store.

Output: Updates the age of the user with ID 1 to 26.

Deleting Data from IndexedDB

Deleting data uses the delete method in a transaction.

Example: Deleting a User

				
					function deleteUser(id) {
    const transaction = db.transaction(["users"], "readwrite");
    const objectStore = transaction.objectStore("users");

    const request = objectStore.delete(id);

    request.onsuccess = function() {
        console.log("User deleted.");
    };

    request.onerror = function() {
        console.error("Error deleting user.");
    };
}

deleteUser(2); // Deletes user with ID 2

				
			

Explanation

  • objectStore.delete: Deletes an entry by key.
  • onsuccess: Confirms successful deletion.

Output: Deletes the specified user and logs “User deleted.”

IndexedDB Transactions

IndexedDB operates on transactions, which are essential for managing multiple database operations and ensuring data consistency. Transactions can be read-only or readwrite and must complete before new operations can start.

  • Read-Only: Used when reading data without modifying it.
  • Read-Write: Used for adding, updating, or deleting data.

Example: Using Transactions

				
					const transaction = db.transaction(["users"], "readonly");
const objectStore = transaction.objectStore("users");

transaction.oncomplete = function() {
    console.log("Transaction completed successfully.");
};

transaction.onerror = function() {
    console.error("Transaction error.");
};

				
			

IndexedDB provides a robust solution for managing large, structured data within the browser, offering far more flexibility and scalability than localStorage. From adding data to reading, updating, and deleting records, IndexedDB operations rely heavily on asynchronous transactions. By understanding and effectively using IndexedDB, developers can create responsive, data-heavy applications that work seamlessly offline and manage data on the client side with precision and efficiency. Happy coding !❤️

Table of Contents