liewchooichin's picture
simple notes app
8196597 verified
// 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);
}
});
}