Spaces:
Running
Running
// Create needed constants | |
const list = document.querySelector('ul'); | |
const titleInput = document.querySelector('#title'); | |
const dateInput = document.querySelector('#date'); | |
const contentInput = document.querySelector('#content'); | |
const form = document.querySelector('form'); | |
const newBtn = document.querySelector('#newBtn'); | |
// Create an instance of a db object for us to store the open database in | |
let db; | |
// Open our database; it is created if it doesn't already exist | |
// (see the upgradeneeded handler below) | |
const openRequest = window.indexedDB.open("notes_db", 1); | |
// error handler signifies that the database didn't open successfully | |
openRequest.addEventListener("error", () => console.error("Database failed to open")); | |
// Create a submit event handler so that when the form is submitted the addData() function is run | |
form.addEventListener("submit", addData); | |
// success handler signifies that the database opened successfully | |
openRequest.addEventListener("success", () => { | |
console.log("Database opened successfully"); | |
// Store the opened database object in the db variable. | |
// This is used a lot below. | |
db = openRequest.result; | |
// Run the displayData() function to display the notes already in the IDB | |
displayData(); | |
}); | |
// Finally for this section, we'll add probably the most important event | |
// handler for setting up the database: upgradeneeded. This handler runs if the | |
// database has not already been set up, or if the database is opened with a | |
// bigger version number than the existing stored database (when performing an | |
// upgrade). Add the following code, below your previous handler: | |
// Set up the database tables if this has not already been done. | |
// Here we first grab a reference to the existing database from the result | |
// property of the event's target (e.target.result), which is the request | |
// object. This is equivalent to the line db = openRequest.result; inside the | |
// success event handler, but we need to do this separately here because the | |
// upgradeneeded event handler (if needed) will run before the success event | |
// handler, meaning that the db value wouldn't be available if we didn't do | |
// this. | |
openRequest.addEventListener("upgradeneeded", (e) => { | |
// Grab a reference to the opened database | |
db = e.target.result; | |
// Create an objectStore in our database to store notes and an | |
// auto-incrementing key | |
// An objectStore is similar to a 'table' in a relational database | |
const objectStore = db.createObjectStore("notes_os", { | |
keyPath: "id", | |
autoIncrement: true, | |
}); | |
// Define what data items the objectStore will contain | |
objectStore.createIndex("title", "title", { unique: false }); | |
objectStore.createIndex("content", "content", { unique: false }); | |
objectStore.createIndex("date", "date", { unique: false }); | |
// Print the outcome of the setup | |
console.log("Database setup completed."); | |
}); | |
// Define the addData() function | |
function addData(e) { | |
// prevent default - we don't want the form to submit in the conventional way | |
e.preventDefault(); | |
// grab the values entered into the form fields and store them in an object ready for being inserted into the DB | |
const newItem = { | |
title: titleInput.value, | |
content: contentInput.value, | |
date: dateInput.value | |
}; | |
// open a read/write db transaction, ready for adding the data, | |
// name of the db: notes_os | |
// IDBDatabase.transaction() | |
const transaction = db.transaction(["notes_os"], "readwrite"); | |
// call an object store that's already been added to the database | |
// IDBTransaction.objectStore() | |
const objectStore = transaction.objectStore("notes_os"); | |
// Make a request to add our newItem object to the object store | |
// IDBObjectStore.add() | |
const addRequest = objectStore.add(newItem); | |
// If the transaction is successful | |
addRequest.addEventListener("success", () => { | |
// Clear the form, ready for adding the next entry | |
titleInput.value = ""; | |
contentInput.value = ""; | |
dateInput.value = ""; | |
}); | |
// Report on the success of the transaction completing, when everything is done | |
transaction.addEventListener("complete", () => { | |
console.log("Transaction completed: database modification finished."); | |
// update the display of data to show the newly added item, by running displayData() again. | |
displayData(); | |
}); | |
// If there is error in the transaction | |
transaction.addEventListener("error", () => console.log("Transaction not opened due to error")); | |
} | |
// Define the displayData() function | |
function displayData() { | |
// Here we empty the contents of the list element each time the display is updated | |
// If you didn't do this, you'd get duplicates listed each time a new note is added | |
while (list.firstChild) { | |
list.removeChild(list.firstChild); | |
} | |
// Open our object store and then get a cursor - which iterates through all the | |
// different data items in the store | |
const transaction = db.transaction("notes_os"); | |
const objectStore = transaction.objectStore("notes_os"); | |
// IDBObjectStore: openCursor(). Returns an IDBRequest object, and, in a | |
// separate thread, returns a new IDBCursorWithValue object. Used for | |
// iterating through an object store with a cursor. | |
objectStore.openCursor().addEventListener("success", (e) => { | |
// Get a reference to the cursor | |
const cursor = e.target.result; | |
// If there is still another data item to iterate through, keep running this code, | |
// In short: | |
// if (cursor) { | |
// cursor.value contains the current record being iterated through | |
// this is where you'd do something with the result | |
// cursor.continue(); | |
//} | |
// else { | |
// no more results | |
//} | |
if (cursor) { | |
// Create a list item, h3, and p to put each data item inside when displaying it | |
// structure the HTML fragment, and append it inside the list | |
const listItem = document.createElement("li"); | |
const h3 = document.createElement("h3"); | |
const para = document.createElement("p"); | |
listItem.appendChild(h3); | |
listItem.appendChild(para); | |
list.appendChild(listItem); | |
// Put the data from the cursor inside the h3 and para | |
h3.textContent = cursor.value.title; | |
para.textContent = `${cursor.value.date}: ${cursor.value.content}`; | |
// Store the ID of the data item inside an attribute on the listItem, so we know | |
// which item it corresponds to. This will be useful later when we want to delete items | |
listItem.setAttribute("data-note-id", cursor.value.id); | |
// Create a button and place it inside each listItem | |
const deleteBtn = document.createElement("button"); | |
listItem.appendChild(deleteBtn); | |
deleteBtn.textContent = "Delete"; | |
// Set an event handler so that when the button is clicked, the deleteItem() | |
// function is run | |
deleteBtn.addEventListener("click", deleteItem); | |
// Iterate to the next item in the cursor | |
cursor.continue(); | |
} | |
else { | |
// Again, if list item is empty, display a 'No notes stored' message | |
if (!list.firstChild) { | |
const listItem = document.createElement("li"); | |
listItem.textContent = "No notes stored."; | |
list.appendChild(listItem); | |
} | |
// if there are no more cursor items to iterate through, say so | |
console.log("Notes all displayed"); | |
} | |
}); | |
} | |
// Define the deleteItem() function | |
function deleteItem(e) { | |
// retrieve the name of the task we want to delete. We need | |
// to convert it to a number before trying to use it with IDB; IDB key | |
// values are type-sensitive. | |
const ulNode = e.target.parentNode; | |
// const noteId = Number(e.target.parentNode.getAttribute("data-note-id")); | |
// We do however need to pass the attribute through the global built-in | |
// Number() object as it is of datatype string, and therefore wouldn't be | |
// recognized by the database, which expects a number. | |
const noteId = Number(ulNode.getAttribute("data-note-id")); | |
// open a database transaction and delete the task, finding it using the id we retrieved above | |
const transaction = db.transaction(["notes_os"], "readwrite"); | |
const objectStore = transaction.objectStore("notes_os"); | |
const deleteRequest = objectStore.delete(noteId); | |
// report that the data item has been deleted | |
transaction.addEventListener("complete", () => { | |
// delete the parent of the button | |
// which is the list item, so it is no longer displayed | |
//e.target.parentNode.parentNode.removeChild(e.target.parentNode); | |
ulNode.parentNode.removeChild(ulNode); | |
console.log(`Note ${noteId} deleted.`); | |
// Again, if list item is empty, display a 'No notes stored' message | |
if (!list.firstChild) { | |
const listItem = document.createElement("li"); | |
listItem.textContent = "No notes stored."; | |
list.appendChild(listItem); | |
} | |
}); | |
} | |