Recipe 5.1
Creating, Reading, and Deleting Objects in a Database
This example is a contact list database implemented with IndexedDB. Contacts can be created, read, and deleted.
Demo
Contacts
Name |
---|
Code
JavaScript
// Once the database is opened, it will be assigned to this variable.
let contactsDb;
/**
* Opens the database, creating the object store if needed.
* Because this is asynchronous, it takes a callback function `onSuccess`. Once the
* database is ready, `onSuccess` will be called with the database object.
*
* @param onSuccess A callback function that is executed when the database is ready
*/
function openDatabase(onSuccess) {
const request = indexedDB.open('contacts-crud');
// Create the object store if needed
request.addEventListener('upgradeneeded', () => {
const db = request.result;
db.createObjectStore('contacts', {
keyPath: 'id',
autoIncrement: true
});
});
request.addEventListener('success', () => {
const db = request.result;
// Call the given callback with the database.
onSuccess(db);
});
request.addEventListener('error', () => {
console.error('Error opening database:', request.error);
});
}
/**
* Reads the contacts from the database.
* @param onSuccess A callback function that is executed when the contacts are loaded
*/
function getContacts(onSuccess) {
const request = contactsDb
.transaction(['contacts'], 'readonly')
.objectStore('contacts')
.getAll();
request.addEventListener('success', () => {
console.log('Got contacts:', request.result);
onSuccess(request.result);
});
request.addEventListener('error', () => {
console.error('Error loading contacts:', request.error);
});
}
/**
* Adds a new contact to the database, then re-renders the table.
* @param contact The new contact object to add
* @param onSuccess A callback function that is executed when the contact is added
*/
function addContact(contact, onSuccess) {
const request = contactsDb
.transaction(['contacts'], 'readwrite')
.objectStore('contacts')
.add(contact);
request.addEventListener('success', () => {
console.log('Added new contact:', contact);
onSuccess();
});
request.addEventListener('error', () => {
console.error('Error adding contact:', request.error);
});
}
/**
* Deletes a contact from the database, then re-renders the table.
* @param contact The contact object to delete
* @param onSuccess A callback function that is executed when the contact is deleted
*/
function deleteContact(contact, onSuccess) {
const request = contactsDb
.transaction(['contacts'], 'readwrite')
.objectStore('contacts')
.delete(contact.id);
request.addEventListener('success', () => {
console.log('Deleted contact:', contact);
onSuccess();
});
request.addEventListener('error', () => {
console.error('Error deleting contact:', request.error);
});
}
// Open the database and do the initial contact list render.
openDatabase(db => {
contactsDb = db;
renderContacts();
});
/**
* Reads the contacts from the database, and renders them in the table.
*/
function renderContacts() {
getContacts(contacts => {
const tbody = document.querySelector('.table tbody');
// Remove the current contact rows
tbody.innerHTML = '';
// If there are no contacts, show a message
if (contacts.length === 0) {
const row = document.createElement('tr');
const cell = document.createElement('td');
cell.colSpan = 3;
cell.innerHTML = 'No contacts found';
row.append(cell);
tbody.append(row);
} else {
// Render one row per contact
contacts.forEach(contact => {
const row = document.createElement('tr');
// Name cell
const name = document.createElement('td');
name.className = 'align-middle';
name.textContent = contact.name;
row.appendChild(name);
// Email cell
const email = document.createElement('td');
email.className = 'align-middle';
email.textContent = contact.email;
row.appendChild(email);
// Actions cell: contains the delete button
const actions = document.createElement('td');
const deleteButton = document.createElement('button');
deleteButton.className = 'btn';
deleteButton.innerHTML = '<i class="bi bi-x-circle"></i>';
deleteButton.addEventListener('click', () => {
deleteContact(contact, renderContacts);
});
actions.appendChild(deleteButton);
row.appendChild(actions);
tbody.append(row);
})
}
});
}
const form = document.querySelector('#contact-form');
form.addEventListener('submit', event => {
event.preventDefault();
const { name, email } = form.elements;
addContact({ name: name.value, email: email.value }, renderContacts);
name.value = '';
email.value = '';
name.focus();
});
HTML
<form id="contact-form">
<div class="container">
<div class="row">
<div class="col">
<input type="text" class="form-control" id="name" name="name" placeholder="Name">
</div>
<div class="col">
<input type="email" class="form-control" id="email" name="email" placeholder="Email">
</div>
<div class="col align-self-end">
<button class="btn btn-primary">Add Contact</button>
</div>
</div>
</div>
</form>
<div class="pt-4">
<h4>Contacts</h4>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>