Building CRUD with ES6 JavaScript and Local Storage
Tags: webdev, javascript, beginners
Published: 2024-03-17 04:38:58

In this tutorial, we'll learn how to create a basic CRUD application using JavaScript ES6 and Local Storage. By the end of this guide, you'll know how to implement CRUD with local storage in your own projects. Let's get code together.

**Prerequisites:**

Basic knowledge in the following: 
HTML 
Javascript
CSS

### Set up

#### File Structure:

Set up your file first with your choosen IDE. 

```
index.css
index.html 
index.js
```

### Inital Code

#### CSS
Copy this [CSS code](https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/start-activity/index.css) into your index.css.

#### HTML

Copy this [index.html](https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/start-activity/index.html) into your index.css.

#### JavaScript

We're utilizing the dialog as our modal, so we don't have to code the modal manually. Simply copy the code below into your index.js.


```
const dialog = document.querySelector('dialog');
const showButton = document.querySelector('#btn-add');
const closeButton = document.querySelector('#btn-close');

showButton.addEventListener('click', () => {
  dialog.showModal();
});

closeButton.addEventListener('click', () => {
  dialog.close();
});
```

### Exploring our Initial App:

Since our focus is to build a small application using JavaScript and localStorage as our database, we'll skip the HTML part and dive directly into explaining how we will build the functionality.

Let's explore our app first. Click the "Add Student" and see the form with fields name, email and course. 

![html form with name, email, course fields](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zysd3nkh6vgjxfcu8g0r.PNG)

Now, let's move on to the table display. You'll notice the following columns: 

- **ID**: Unique identification of the student data
- **Name, Email, Course**: Personal Info of the student
- **Actions**: Perform Edit and Delete record in this columns


Since you already know what our app. Let's start to code. 

#### START
Copy this code first; we'll use it later. Make sure it's positioned below your main code for better organization.

```
/* Modal dialog code */

/* put your code here... */


// utilities 
function populateTable() {
  let tableRow = '';
  getStudentList().forEach((student) => {
    tableRow += tableRowHTML(student);
  });

  table.innerHTML = tableRow;
}

const generateRandomId = () => Math.floor(Math.random() * 99999);

const formDataToObject = (formData) => {
  const object = {};
  formData.forEach((value, key) => {
    object[key] = value;
  });
  return object;
};

function resetForm() {
  document.querySelector('#student-id').value = '';
  studentForm.reset();
}

function tableRowHTML(student) {
  return `<tr id='std_${student.id}'>
            <td>${student.id}</td>
            <td>${student.name}</td>
            <td>${student.email}</td>
            <td>${student.course}</td>
            <td class="actions">
            <button student-id="${student.id}" action-type="edit" class="edit-btn">Edit</button>
            <button student-id="${student.id}" action-type="delete" class="delete-btn">Delete</button>
            </td>
        </tr>`;
}

function getStudentList() {
  return JSON.parse(localStorage.getItem('studentList')) || [];
}
```

**Declarations:**

```
// dialog code 

const studentForm = document.getElementById('student-form');
const table = document.querySelector('table tbody');
```

Getting the studentForm and table from our DOM, we'll add event listeners later.

### CREATE

**Add Form Function**
```
const addForm = (formData) => {
  formData.append('id', generateRandomId());

  const student = formDataToObject(formData);
  studentList.push(student);

  localStorage.setItem('studentList', JSON.stringify(studentList));

  const newRow = table.insertRow(-1);

  newRow.id = 'std_' + student.id;
  newRow.innerHTML = tableRowHTML(student);
};
```

The function above, addForm, adds new student data to the application. It generates a random ID for the student, appends it to the form data, and converts the form data into a student object. The student object is then added to the studentList array, which is stored in local storage. Additionally, a new row is inserted into the HTML table to display the new student's information. 


**FORM SUBMISSION:**
`addSubmit` function to the form.

```
studentForm.addEventListener('submit', (event) => {
  event.preventDefault();

  const formData = new FormData(studentForm);

  addForm(formData);
  
  resetForm();
  dialog.close();
});
```


To test if it's working, go to the localStorage in the inspect tab under the "Application" section, and check if the data has been added successfully. If it's working, proceed to the next step.

### READ

We have a function called `populateTable`. Its purpose is to display the existing data in the localStorage during the first load of our application. It retrieves data from the `getStudentList()` function.

Call **`populateTable()`** after all the our variable declarations. 

```
const studentForm = document.getElementById('student-form');
const table = document.querySelector('table tbody');

populateTable(); // add this code
```

This will display the student info on the first load of the application if there's an existing data. 


### UPDATE 
Displaying Student Information in a Modal for Editing.

```
table.addEventListener('click', (event) => {
  const target = event.target;
  const id = target.getAttribute('student-id');

  if (target.classList.contains('edit-btn')) {
    dialog.showModal();

    const student = getStudentList().find((student) => id == student.id);

    document.getElementById('student-id').value = student.id;
    document.getElementById('name').value = student.name;
    document.getElementById('email').value = student.email;
    document.getElementById('course').value = student.course;
  }
});

```

The code snippet above enables editing of student details directly within the table. When a user clicks an `edit` button in a row, it triggers a dialog displaying the student's information fetched from the `getStudentList()` function based on the student ID. The data retrieved is then utilized to update the input values for each field using `document.getElementById('input-id')`.


### EDIT
```
const editForm = (formData) => {
  const studentForm = formDataToObject(formData);
  const studentList = getStudentList();

  const studentIndex = getStudentList().findIndex(
    (student) => studentForm.id == student.id
  );

  if (studentIndex == -1) return;

  studentList[studentIndex] = {
    ...studentList[studentIndex],
    ...studentForm,
  };

  localStorage.setItem('studentList', JSON.stringify(studentList));

  document.querySelector('#std_' + studentForm.id).innerHTML =
    tableRowHTML(studentForm);
};
```

The `editForm` function edits student details by updating the student list with new form data and saving it back to local storage. It first converts form data to an object, retrieves the student list, finds the index of the student being edited, updates their information using `tableRowHTML`, and then updates the corresponding row in the HTML table with the new data.

**FORM SUBMISSION:**
```
studentForm.addEventListener('submit', (event) => {
  event.preventDefault();

  const formData = new FormData(studentForm);

  const isEditMode = formData.get('id') != ''; 

  if (isEditMode) {
    editForm(formData);
  } else {
    addForm(formData);
  }

  resetForm();
  dialog.close();
});

```

We've improved our form to handle both updating and adding student data using just one form. Now, if the form has an `id` field, it's for editing, so we call the editForm function. Otherwise, if there's no `id` field, it's for adding new data, so we call the addForm function. This tweak makes it easier for users to manage student information in our application.

### DELETE

```
table.addEventListener('click', (event) => {
  const target = event.target;
  const id = target.getAttribute('student-id');

  if (target.classList.contains('edit-btn')) {... code for edit ...}
  } else if (target.classList.contains('delete-btn')) {
    const row = target.parentNode.parentNode;
    const newStudentList = getStudentList().filter(
      (student) => id != student.id
    );

    document.querySelector('table').deleteRow(row.rowIndex);

    localStorage.setItem('studentList', JSON.stringify(newStudentList));
}); 

```

Let's modify our code for `table.addEventListener()`. We've added a new condition for the delete button if it's triggered. Then, we'll retrieve the row of the table using `target.parentNode.parentNode`. Afterward, we'll use filter to return a new list without the student ID of the selected student item in the table. Following this, we'll delete the selected row using `deleteRow`. Lastly, we'll update the new localStorage with our new student list. This functionality allows our users to delete user records directly from the table interface while keeping the data synchronized.


### END OF CODE

That's all for the CRUD functionality. I hope you found this tutorial helpful. If you encounter any issues, feel free to refer to our source code for comparison. I also include the demo link below so you can test the application yourself. 

[CLICK HERE FOR DEMO](https://javascript-es6-crud.netlify.app/)
[INITAL CODE](https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/start-activity/index.css)
[CRUD SOURCE CODE](https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/main/index.css)

Thank you for reading my blog.

If you have any suggestions or corrections, please leave a comment below. I'll gladly respond and consider your input.