Home » HTML5 IndexedDB Tutorial

HTML5 IndexedDB Tutorial

by shedders

IndexedDB is a low-level API for storing structured data in the browser. It allows you to store large amounts of data and retrieve it efficiently using key-value pairs.

Unlike localStorage, IndexedDB is asynchronous and supports advanced features like transactions, indexing, and searching.

In this tutorial, you’ll learn:

  1. What is IndexedDB and its benefits.
  2. Setting up and creating a database.
  3. Performing CRUD (Create, Read, Update, Delete) operations.
  4. Using indexes for efficient data retrieval.
  5. Practical examples with IndexedDB.

1. What is IndexedDB?

IndexedDB is:

  • Asynchronous: Operates without blocking the main thread.
  • Persistent: Stores data even after the browser is closed.
  • Structured: Supports objects, arrays, and complex data types.
  • Powerful: Offers transactions, versioning, and indexing for fast lookups.

Use Cases:

  • Offline web applications.
  • Storing large datasets like user preferences, chat history, or product catalogs.
  • Caching API responses.

2. Setting Up IndexedDB

Example 1: Creating a Database

// Open or create a database
const request = indexedDB.open("MyDatabase", 1);

// Handle success
request.onsuccess = function (event) {
    console.log("Database opened successfully:", event.target.result);
};

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

// Set up the database structure
request.onupgradeneeded = function (event) {
    const db = event.target.result;

    // Create an object store with a key path
    const store = db.createObjectStore("Users", { keyPath: "id" });

    // Create indexes for quick lookups
    store.createIndex("name", "name", { unique: false });
    store.createIndex("email", "email", { unique: true });

    console.log("Object store and indexes created.");
};

Explanation:

  • indexedDB.open(“MyDatabase”, version): Opens or creates a database with the specified version.
  • onupgradeneeded: Triggered if the database needs a new schema.

3. Performing CRUD Operations

Example 2: Adding Data to IndexedDB

const request = indexedDB.open("MyDatabase", 1);

request.onsuccess = function (event) {
    const db = event.target.result;

    // Start a transaction
    const transaction = db.transaction("Users", "readwrite");
    const store = transaction.objectStore("Users");

    // Add data
    store.add({ id: 1, name: "John Doe", email: "john@example.com" });
    store.add({ id: 2, name: "Jane Smith", email: "jane@example.com" });

    transaction.oncomplete = function () {
        console.log("Data added successfully.");
    };

    transaction.onerror = function (event) {
        console.error("Transaction error:", event.target.error);
    };
};

Explanation:

  • transaction.objectStore(name): Accesses the specified object store.
  • store.add(data): Adds data to the store.

Example 3: Reading Data from IndexedDB

const request = indexedDB.open("MyDatabase", 1);

request.onsuccess = function (event) {
    const db = event.target.result;

    // Start a transaction
    const transaction = db.transaction("Users", "readonly");
    const store = transaction.objectStore("Users");

    // Get a specific item by key
    const getRequest = store.get(1);
    getRequest.onsuccess = function (event) {
        console.log("Retrieved data:", event.target.result);
    };

    getRequest.onerror = function (event) {
        console.error("Get request error:", event.target.error);
    };
};

Explanation:

  • store.get(key): Retrieves an item by its key.

Example 4: Updating Data in IndexedDB

const request = indexedDB.open("MyDatabase", 1);

request.onsuccess = function (event) {
    const db = event.target.result;

    // Start a transaction
    const transaction = db.transaction("Users", "readwrite");
    const store = transaction.objectStore("Users");

    // Update an existing item
    const updateRequest = store.put({ id: 1, name: "John Doe", email: "john.doe@example.com" });

    updateRequest.onsuccess = function () {
        console.log("Data updated successfully.");
    };

    updateRequest.onerror = function (event) {
        console.error("Update error:", event.target.error);
    };
};

Explanation:

  • store.put(data): Updates or adds data if the key already exists.

Example 5: Deleting Data from IndexedDB

const request = indexedDB.open("MyDatabase", 1);

request.onsuccess = function (event) {
    const db = event.target.result;

    // Start a transaction
    const transaction = db.transaction("Users", "readwrite");
    const store = transaction.objectStore("Users");

    // Delete an item by key
    const deleteRequest = store.delete(1);

    deleteRequest.onsuccess = function () {
        console.log("Data deleted successfully.");
    };

    deleteRequest.onerror = function (event) {
        console.error("Delete error:", event.target.error);
    };
};

Explanation:

  • store.delete(key): Deletes an item by its key.

4. Using Indexes

Indexes allow you to query data efficiently.

Example 6: Querying Data by Index

const request = indexedDB.open("MyDatabase", 1);

request.onsuccess = function (event) {
    const db = event.target.result;

    // Start a transaction
    const transaction = db.transaction("Users", "readonly");
    const store = transaction.objectStore("Users");
    const index = store.index("email");

    // Get an item by index
    const indexRequest = index.get("jane@example.com");

    indexRequest.onsuccess = function (event) {
        console.log("Queried data:", event.target.result);
    };

    indexRequest.onerror = function (event) {
        console.error("Index query error:", event.target.error);
    };
};

Explanation:

  • store.index(name): Accesses an index.
  • index.get(value): Retrieves data based on an indexed value.

5. Deleting an Object Store

To delete an object store, update the database schema.

Example 7: Delete an Object Store

const request = indexedDB.open("MyDatabase", 2);

request.onupgradeneeded = function (event) {
    const db = event.target.result;

    // Delete an existing object store
    if (db.objectStoreNames.contains("Users")) {
        db.deleteObjectStore("Users");
        console.log("Object store deleted.");
    }
};

6. Practical Application: Todo App

Example 8: A Simple Todo App with IndexedDB

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>IndexedDB Todo App</title>
</head>
<body>
    <h1>Todo App</h1>
    <input type="text" id="todoInput" placeholder="Enter a todo">
    <button id="addTodo">Add Todo</button>
    <ul id="todoList"></ul>

    <script src="todoApp.js"></script>
</body>
</html>

JavaScript (todoApp.js)

const request = indexedDB.open("TodoDB", 1);

request.onupgradeneeded = function (event) {
    const db = event.target.result;
    db.createObjectStore("Todos", { keyPath: "id", autoIncrement: true });
};

request.onsuccess = function (event) {
    const db = event.target.result;

    const addTodo = () => {
        const todoInput = document.getElementById("todoInput");
        const transaction = db.transaction("Todos", "readwrite");
        const store = transaction.objectStore("Todos");

        store.add({ text: todoInput.value });
        todoInput.value = "";
        displayTodos();
    };

    const displayTodos = () => {
        const transaction = db.transaction("Todos", "readonly");
        const store = transaction.objectStore("Todos");

        const todoList = document.getElementById("todoList");
        todoList.innerHTML = "";

        store.openCursor().onsuccess = function (event) {
            const cursor = event.target.result;
            if (cursor) {
                const li = document.createElement("li");
                li.textContent = cursor.value.text;
                todoList.appendChild(li);
                cursor.continue();
            }
        };
    };

    document.getElementById("addTodo").addEventListener("click", addTodo);
    displayTodos();
};

7. Best Practices

  1. Use Transactions: Always use transactions for consistency.
  2. Handle Errors: Provide meaningful error messages.
  3. Schema Versioning: Use the version parameter to manage schema changes.
  4. Browser Compatibility: Test your application across different browsers.

8. Conclusion

In this tutorial, you learned:

  1. How to set up and use IndexedDB.
  2. CRUD operations and using indexes for efficient queries.
  3. How to apply IndexedDB in a practical example like a Todo App.

IndexedDB is a powerful tool for building offline-capable and data-intensive web applications.

You may also like