Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

A complete guide to using IndexedDB

TODO APP

TODO APP

TODOs

    Add Todo

    This creates the base structure of our web app. We do two main things here: first, we create a section to display/view all to-dos saved in the database, and second, we create a section for adding to-dos to the database. Let’s also add some basic styling to the application. Open the styles.css file and add the following: html { font-family: sans-serif; } body { margin: 0 auto; max-width: 800px; } header, footer { background-color: blue; color: white; padding: 0 20px; } .add, .view { padding: 30px; width: 40%; } .add { background: #ebe6e6; } section { padding: 10px; background: #3182d4; display: flex; flex-direction: row; flex-wrap: wrap; justify-content: center; } h1 { margin: 0; } ol { list-style-type: none; } div { margin-bottom: 10px; }The index.js file is the heart of the application, as it contains the logic for interacting between the app and IndexedDB. First, we need to create the database; then, we can initialize it by creating an object store (similar to a table in SQL), which we‘ll use to store each item detail. Open the index.js file and add the following logic to it:let db;const openOrCreateDB = window.indexedDB.open('todo_db', 1);openOrCreateDB.addEventListener('error', () => console.error('Error opening DB'));openOrCreateDB.addEventListener('success', () => { console.log('Successfully opened DB'); db = openOrCreateDB.result;});openOrCreateDB.addEventListener('upgradeneeded', init => { db = init.target.result; db.onerror = () => { console.error('Error loading database.'); }; const table = db.createObjectStore('todo_tb', { keyPath: 'id', autoIncrement:true }); table.createIndex('title', 'title', { unique: false }); table.createIndex('desc', 'desc', { unique: false });});As can be seen above, a database named todo_db is created, and then an object store named todo_tb is created with two indexes, title and desc. These indexes allow their values to be duplicated in the store, which is similar to creating a table in SQL and then creating two columns. Next, to add the Save functionality, we proceed to retrieve the values entered into the form and then save them to the database:const todos = document.querySelector('ol');const form = document.querySelector('form');const todoTitle = document.querySelector('#title');const todoDesc = document.querySelector('#desc');const submit = document.querySelector('button');form.addEventListener('submit', addTodo);function addTodo(e) { e.preventDefault(); const newTodo = { title: todoTitle.value, body: todoDesc.value }; const transaction = db.transaction(['todo_tb'], 'readwrite'); const objectStore = transaction.objectStore('todo_tb'); const query = objectStore.add(newTodo); query.addEventListener('success', () => { todoTitle.value = ''; todoDesc.value = ''; }); transaction.addEventListener('complete', () => { showTodos(); }); transaction.addEventListener('error', () => console.log('Transaction error'));}After adding the values to the store, the two form fields are emptied so the user can enter a new item to their list. We can update the view by calling the showTodos method, which we’ll see in the next section. Retrieving and displaying data To confirm if the Save to-do function worked, open and use your browser’s Inspect function. In Chrome, you can see IndexedDB under the Application tab, in Storage. As can be seen in the image below, we created the database and saved the first to-do to the todo_tb object store: To display the available to-dos when the user loads the page, and provide a view of previously added and removed to-dos, we’ll create a method called showTodos:function showTodos() { while (todos.firstChild) { todos.removeChild(todos.firstChild); } const objectStore = db.transaction('todo_tb').objectStore('todo_tb'); objectStore.openCursor().addEventListener('success', e => { const pointer = e.target.result; if(pointer) { const listItem = document.createElement('li'); const h3 = document.createElement('h3'); const pg = document.createElement('p'); listItem.appendChild(h3); listItem.appendChild(pg); todos.appendChild(listItem); h3.textContent = pointer.value.title; pg.textContent = pointer.value.body; listItem.setAttribute('data-id', pointer.value.id); const deleteBtn = document.createElement('button'); listItem.appendChild(deleteBtn); deleteBtn.textContent = 'Remove'; deleteBtn.addEventListener('click', deleteItem); pointer.continue(); } else { if(!todos.firstChild) { const listItem = document.createElement('li'); listItem.textContent = 'No Todo.' todos.appendChild(listItem); } console.log('Todos all shown'); } });}This method gets the to-dos from the store, loops through each item, and creates an HTML element for each. It appends the item to the ol list element on the webpage and passes the id of each to-do into a data attribute called data-id. We’ll use this unique ID later, when we cover the deleteItem function, to identify each to-do when we need to remove it from the store. To fetch the to-dos on page load, modify the openOrCreateDB success event listener to this:openOrCreateDB.addEventListener('success', () => { console.log('Successfully opened DB'); db = openOrCreateDB.result; showTodos();}); Deleting data from the database Finally, let’s test the DELETE API for this database and create a Delete function for our to-do list app:function deleteItem(e) { const todoId = Number(e.target.parentNode.getAttribute('data-id')); const transaction = db.transaction(['todo_tb'], 'readwrite'); const objectStore = transaction.objectStore('todo_tb'); objectStore.delete(todoId); transaction.addEventListener('complete', () => { e.target.parentNode.parentNode.removeChild(e.target.parentNode); alert(`Todo with id of ${todoId} deleted`) console.log(`Todo:${todoId} deleted.`); if(!todos.firstChild) { const listItem = document.createElement('li'); listItem.textContent = 'No Todo.'; todos.appendChild(listItem); } }); transaction.addEventListener('error', () => console.log('Transaction error'));}This deletes the particular to-do using the unique ID passed to the method and removes the element from the webpage. Once it deletes the last to-do item in the store, it shows a “no to-dos” message in the place of the to-do list. To confirm that the to-do has been deleted from the database, proceed to inspect the webpage and click the Application tab. As can be seen, the todo_tb object store now contains no items: The final web application looks like this: Incrementing the IndexedDB version IndexedDB also allows developers to increment the database version. When you open the database, specify your desired version number:window.indexedDB.open('todo_db', 1);If the database doesn't exist, it will be created with the specified version. If the database already exists, the version number is checked. If the version number specified during the open method call is higher than the existing version, a version change event is triggered via the onUpgradeNeeded event. This event allows you to perform database schema changes or data migrations. A point to note here is deleting a previous object store to add new options when creating a new store would also delete all other data in the old store. Take care to read the old content out and save it somewhere else before upgrading the database. Drawbacks of using IndexedDB Since IndexedDB relies on the client's web browser, it is typically more suitable for individual users or smaller-scale applications. Though it can handle a significant amount of data, there are certain considerations to keep in mind when using IndexedDB in large-scale apps or apps used by multiple people. Scalability limitationsIndexedDB operates within a web browser, which means it is limited to the capabilities and resources of the client-side environment. It may not scale well for scenarios that require handling large numbers of simultaneous users or extremely high throughput. Data size limitationsDifferent web browsers impose limits on the maximum amount of data that can be stored in IndexedDB. These limits vary across browsers and can range from a few megabytes to several hundred megabytes. It is greatly important to be aware of these limitations and design the application accordingly. Once your data storage runs out, you won't be able to store new data in the database, as you would trigger a QuotaExceededError error. Synchronization challengesIndexedDB doesn’t provide inbuilt mechanisms for handling data synchronization between clients or handling conflicts in a distributed environment. You would need to implement custom synchronization logic to handle these scenarios. Maintaining data consistency and synchronization across different instances of the application becomes complex. Hence, for larger-scale applications or applications used by multiple people, it is more efficient to use server-side databases or cloud-based storage solutions. ConclusionIn this article, we learned about IndexedDB, a database on the web, and how to interact with it to store web application data using JavaScript. Hopefully, you enjoyed this article and have learned a new way of managing your application data locally on the web. Thanks for reading!


    This post first appeared on VedVyas Articles, please read the originial post: here

    Share the post

    A complete guide to using IndexedDB

    ×

    Subscribe to Vedvyas Articles

    Get updates delivered right to your inbox!

    Thank you for your subscription

    ×