How I Built A Simple Note App Using JavaScript

How I Built A Simple Note App Using JavaScript

Please pardon my writing skills,i just started out recently.

Note: You can also build this app or create it's functionality using Angular or any other framework/library.

App Description: A simple browser based note app which allows you to create and store your notes probably for later purpose.

App Idea: FreeCodeCamp

**App Repo: ** Link

Before we move on lets just list out it features.

  • The user can create a note

  • The user can edit a note

  • The user can delete a note.

How is this going to work ?

After a User creates a note or edits a note, when closing the browser window the notes are stored and when the User returns the notes gets retrieved.

So a User:

  • Adds or creates a note by clicking on a button.

  • Edits a note by clicking or focus on a note.

  • Saves note by clicking outside of that note.

  • Deletes note by clicking on a delete button.

More like performing crud operation but this time lets see how we can use the browsers' storage to perform this operation,lets get started.

HTML

First what are the things we need on the web page

  1. An area or card which will serve as the note.

  2. Few Buttons like add and delete.

<div class="container">
      <div class="notes">
              <div class="note">
                  <div class="note-header">
                     <div class="header-content">Tue Jun 25 2019</div>
                      <div class="header-content">
                          <i class="fa fa-edit"></i>
                           <i class="fa fa-trash"></i>
                       </div>
                    </div> 
               <div class="note-body"> 
                 <div class="note-area"></div>
                </div>
               </div>
        </div>
        <div class="add-note">
             <i class="fa fa-plus fa-1x"></i>
         </div>
</div>

Lets talk about the code above.

So we created a markup of the app by adding some few html codes

we have the .container class which will serve as a wrapper to other page content alongside that we have the .notes class which will serve as a parent container to the notes. The .note class will be generated dynamically by JavaScript depending on the number of notes created by a user, so we are gonna move that to our JavaScript code in a moment.

Next we have the .add-note class which is the add button.

Before we jump into styling the app lets just work on the JavaScript part first.

JavaScript

Before i drop down codes lets list out some few things we are going to do with JavaScript.

  • First thing we want to do is to be able to add notes

  • Display Notes.

  • Update notes and save notes

  • Delete notes

  • Be able to retrieve notes if notes exists when a user returns to the browser.

With this in mind i think we ready to drop some codes. But first since we going to be making use of the browsers storage won't it be nice we first check if it available for us to use.

https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API

const storageAvailable = (type) => {
     let  storage;

     try {

         storage = window[type];
         const x = '__storage_test__';
         storage.setItem(x,x);
         storage.removeItem(x);

         return true;

     } catch (e) {

        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            (storage && storage.length !== 0);
     }
 }

The function above will help us check if storage is both supported and available for us to use . if we have storage available it return true else an Exception . notice we can use this function to check for any storage type available for us to use e.g we can use it to check for sessionStorage , localStorage.

Here we are making use of the localStorage so we check like this

if (storageAvailable('localStorage')) {
   // we  place our code here if we have storage available to us
}
else {
  // here you can pass a message
}

Finally.

Adding Notes

if (storageAvailable('localStorage')) {
// added an event listener to the add note button
        document.querySelector('.add-note').addEventListener('click',()=>{
                // get notes content 
                const notesItem = localStorage.getItem('notes'),newNotes = {};
                let  notes = [];
                newNotes.createdOn = Date.now();
                newNotes.text = ' ';
///check if notes not  null and not empty
                if (notesItem !== null && notesItem !=='' ) {
/// if not null and not empty run this
                    notes = JSON.parse(notesItem);
                } 
//
                notes.push(newNotes);
                localStorage.setItem('notes',JSON.stringify(notes));  

        });

Lets break the code above down

  1. First checked if storage is available and supported,if it is we use it.

  2. Next we placed an event listener to the add-note button on click

  3. Next we declared some few variables and assigned values to them

    • const notesContent = This stores the item we get from localStorage.The reason we did this is to be able to check if the user has already created or have other notes stored and we don't get to overide them instead we add to them.

    • const newNotes = declares or create an object, this is because we intend to store this items as key/value pair in localStorage.

    • let notes = an empty array which will help store our objects.Notice we using the let key word here? The reason is because we are going to change it values later on our code.

  4. We created our Object key and value pair newNotes.createdOn \= Date.now() which gets your current timestamp and newNotes.text= empty string.

  5. Next we checked if notes has already been initially created before by checking if it not null and empty,if true we assign the items to the notes variable.

  6. Next we push or append the newNotes Object into the empty array using notes.push(newNotes)

Note*

if we tend to store our data just by having the localStorage.setItem() set just the array or object like this localStorage.setItem('notes',notes) what we will have stored for us will be this [object object] string which we can't use when we retrieve it.Note* you can store integers,strings,booleans in localStorage with no problems.

with that in mind how do we store our object or array and retrieve them?.

To store the object or array we first convert it to a string which can easily be done with JSON.stringify() e.g JSON.stringify(notes).With this we can retrieve our objects nicely and be able to use them by constructing the object described or stored as a string like this JSON.parse(notesItem);

Display Notes.

Now we want to create the elements we need and have them inserted into the div.notes in our HTML code. So we are going to have to edit or add some codes in the click event listener which will create those needed elements and have them displayed to the user after clicking the add-note button.

document.querySelector('.add-note').addEventListener('click',()=>{
                const notesItem = localStorage.getItem('notes'),newNotes = {};
                let  notes = [];
                newNotes.createdOn = Date.now();
                newNotes.text = ' ';
                if (notesItem !== null && notesItem !=='') {
                    notes = JSON.parse(notesItem);
                } 
                notes.push(newNotes);
                localStorage.setItem('notes',JSON.stringify(notes));
                const   childDiv = document.createElement('div');
                        childDiv.setAttribute('class','note note-'+newNotes.createdOn);
                const parentDiv = document.querySelector('.notes')
                              parentDiv.insertBefore(childDiv,parentDiv.childNodes[0]);
                const   noteBody = document.getElementsByClassName('note');
                        noteBody[0].innerHTML = noteContentArea(newNotes);
                        document.getElementsByClassName('note-area')[0].contentEditable = true;


        });

lets talk about it

  • First created the childDiv set the class attribute and value

  • Got the parentDiv and used insertBefore() method to insert the childDiv we created before every other child element of the parentDiv

  • Next we made the noteBody by getting the note by class name having it innerHTML to be the noteContentArea which is a function created in other for us to reuse it or repeat ourselves.

Here is the function

const noteContentArea= (note) => {
     const dateTime = new Date(note.createdOn);
     let content = '<div class="note-header"><div class="header-content">'+ dateTime.toDateString() +'</div>';
         content         +='<div class="header-content"><i class="fa fa-edit icon-'+note.createdOn+'"></i><i class="fa fa-trash" onclick="deleteNote('+note.createdOn+')"></i>';
         content          +='</div></div> <div class="note-body"> <div class="note-area"  onblur="update(this)" id="'+note.createdOn+'">'+note.text+'</div></div>';

           return content;
 }

All we did was to have the other relevant elements in a function noteContentArea passed some contents from the note parameter and also some other attributes onclick which will handle the deletion of the notes whenever the trash icon is clicked and onblur which will save the note or update the note when the user clicks outside the note area.

  • After all that we made the note-area editable using contentEditable property Learn More

** Update And Save Note**

const update = (div) => {
     const text = div.innerHTML;

     const getNotes = JSON.parse(localStorage.getItem('notes'));
     const updatedNotes = [];

     getNotes.forEach(note =>{
         if (note.createdOn == div.id) {
             note.text = text;
             updatedNotes.push(note);
         } else {
            updatedNotes.push(note);
         }

     });
     localStorage.setItem('notes',JSON.stringify(updatedNotes));
     const icon =document.querySelector('.icon-'+div.id);
     setTimeout(()=>{
        icon.setAttribute('class','fa fa-edit icon-'+div.id);
        icon.style.color = '#000';
     },3000);
        icon.setAttribute('class','fa fa-check icon-'+div.id);
        icon.style.color = '#00C851';
 }
  • We created a variable to help us hold the content of the HTML element which we made editable const text

  • Get the previously stored notes const getNotes

  • Created an empty array which will store the updated note

  • Next we looped through the getNotes array to get the specific note which is been updated using the control statement

  • Using the control statement what we did was to check if the note item key createdOn which we are using as a primary key in the getNotes array is same with the current note been edited.So if it is same we assign the new value of the HTML element been edited which we have stored in text variable to note.text and we push to the empty array updatedNotes.push(note) and else it is not same we just push the item into the empty array.

  • Next we save the newly edited item in the browser's storage localStorage.setItem('notes',JSON.stringify(updatedNotes)); and wrote some codes to help switch the icons .

** Delete Notes **

const deleteNote = (timestamp) => {
    const getNoteItems = JSON.parse(localStorage.getItem('notes'));
    notesArr = [];
    getNoteItems.forEach(note =>{
        if (note.createdOn !== timestamp) {
            notesArr.push(note);
        } 
    });

    localStorage.setItem('notes',JSON.stringify(notesArr));

    let node = document.getElementsByClassName('note-'+timestamp);
    if (node[0].parentNode) {
        node[0].parentNode.removeChild(node[0]);
    }

 }
  • So what we did in the delete note function is similar only this time after getting and looping through the items we check if the note key createdOn not same with the current one been deleted,if it is not we have the items stored in the noteArr and also have it stored on the browser's storage localStorage.setItem('notes',JSON.stringify(notesArr)) ,that way we don't have the already deleted items saved in the browsers storage and also retrieved when the user returns .

  • Next we removed it from the DOM by invoking the removeChild method on the parentNode of the element been gotten by class name node. node[0].parentNode.removeChild(node[0]);

Retrieve Notes

notes = JSON.parse(localStorage.getItem('notes'));
    if( notes !== null ) {
        notes.reverse();
        let i = 0;
        notes.forEach(note => {
            const cards = document.createElement('div');
                cards.setAttribute('class','note note-'+note.createdOn);
                document.querySelector('.notes').appendChild(notes);
            const card = document.getElementsByClassName('note');
            card[i].innerHTML = cardContent(note);
            document.getElementsByClassName('note-area')[i].contentEditable = true;
            i++;
        });
    }
  • Similar to what we did on Display Note but this time after getting the note from our browsers storage we first check if it not null or not empty.

  • if it meets our conditions we loop through each items and create the elements on the DOM based on the items we have in the notes array.

Note : You can place the above code in the window.onload function to display to the user when or after the user returns to the browser or reloads the browser.

So i guess that will be it. Oh as for the CSS you can get the source code on the link below or actually just apply your own styling to the element following the Demo design pattern or just create yours.

**Source Code : ** here

Possible Features You Might Want To implement

  • Have Users make or write note in markdown format

  • Have the notes stored somewhere other than the browser's storage.

Finally friends we done.