1. Welcome
In this lab, you'll back up and recover client data to IndexedDB. This is the third in a series of companion codelabs for the Progressive Web App workshop. The previous codelab was Working with Workbox. There are five more codelabs in this series.
What you'll learn
- Create an IndexedDB database and object store using
idb
- Add and retrieve items to an object store
What you should know
- JavaScript and Promises
What you will need
- A browser that supports IndexedDB
2. Get Set Up
Start by either cloning or downloading the starter code needed to complete this codelab:
If you clone the repo, make sure you're on the pwa03--indexeddb
branch. The zip file contains the code for that branch, too.
This codebase requires Node.js 14 or higher. Once you have the code available, run npm ci
from the command line in the code's folder in order to install all of the dependencies you'll need. Then, run npm start
to start the development server for the codelab.
The source code's README.md
file provides an explanation for all distributed files. In addition, the following are the key existing files you'll be working with throughout this codelab:
Key Files
js/main.js
- Main application JavaScript file
3. Set Up Database
Before an IndexedDB database can be used, it needs to be opened and set up. While you can do this directly, because IndexedDB was standardized before Promises were prominent, it's callback based interface can be unwieldy to use. Instead, we'll be using idb, a very small Promise wrapper for IndexedDB. To start, first import it into js/main.js
:
import { openDB } from 'idb';
Then, add the following setup code to the top of the DOMContentLoaded
event listener:
// Set up the database
const db = await openDB('settings-store', 1, {
upgrade(db) {
db.createObjectStore('settings');
},
});
Explanation
Here, an IndexedDB database called settings-store
is created. Its version is initialized to 1
and its initialized with an object store called settings
. This is the most basic kind of object store, simple key-value pairs, but more complex object stores can be created as needed. Without this initialization of an object store, there will be nowhere to put data in, so leaving this out here would be like creating a database with no tables.
4. Save Editor State on Update
With the database initialized, it's time to save content to it! The editor exposes an onUpdate
method that lets you pass a function to be called whenever content gets updated in the editor. It's the perfect place to tap in and add the changes to the database. To do so, add the following code right before the defaultText
declaration in js/main.js
:
// Save content to database on edit
editor.onUpdate(async (content) => {
await db.put('settings', content, 'content');
});
Explanation
db
is the previously opened IndexedDB database. The put
method allows entries in an object store in that database to be created or updated. The first argument is the object store in the database to use, the second argument is the value to store, and the third argument is the key to save the value to if it's not clear from the value (in this case it's not as our database doesn't include specified keys). Because it's asynchronous, it's wrapped in async
/await
.
5. Retrieve State on Load
Finally, in order to recover the user's in-progress work, it needs to be loaded when the editor loads. The editor supplies a setContent
method to do just that, set it's content. It's currently used to set it to the value of defaultText
. Update it with the following to load the user's previous work in instead:
editor.setContent((await db.get('settings', 'content')) || defaultText);
Explanation
Instead of just setting the editor to the value of defaultText
, it now attempts to get the content
key from the settings
object store in the settings-store
IndexedDB database. If that value exists,, that's used. If not, the default text is used.
6. Set and Retrieve Night Mode State
Now that you're comfortable with IndexedDB, add the following code to the bottom of js/main.js
and update it to save the user's night mode preference when it changes, and load that preference when night mode initializes.
// Set up night mode toggle
const { NightMode } = await import('./app/night-mode.js');
new NightMode(
document.querySelector('#mode'),
async (mode) => {
editor.setTheme(mode);
// Save the night mode setting when changed
},
// Retrieve the night mode setting on initialization
);
7. Congratulations!
You've learned how to save and load data from an object store in IndexedDB.
The next codelab in the series is From Tab to Taskbar