DEV Community

loading...
Cover image for Creating a family list app with vanilla JavaScript

Creating a family list app with vanilla JavaScript

ubahthebuilder profile image Kingsley Ubah Updated on ・6 min read

I am Kingsley Ubah, a budding software developer and tech enthusiast. I recently created a simple Family list app entirely out of vanilla Javascript. I didn’t use any Frameworks or Libraries. So, this article comprehensively covers how I did it. You can view and download the source code at my codepen. This project is a replica of Brad Traversy’s Book list app used in his tutorial.

Typically, we use libraries like jQuery to manipulate our DOM from our JavaScript and this has been the status quo for quite some time now. Brad Traversy displayed with his videohow you can create a responsive app with nothing but pure JavaScript and I was so fascinated with the idea of building with no dependency libraries or frameworks. This app is a result of that.

FAMILY LIST APP

Alt Text

This is going to be a very simple app. The app consists of just two source files, the HTML file (index.html) and JavaScript file (app.js). In our HTML file, we are going to import FontAwesome for Icons and Bootstrap for styling. I used Bootswatch utility to search for a specific feel of Bootstrap.

Alt Text

Include URLs to stylesheets inside the link elements in your HTML page.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA==" crossorigin="anonymous" />
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/litera/bootstrap.min.css" integrity="sha384-enpDwFISL6M3ZGZ50Tjo8m65q06uLVnyvkFO3rsoW0UC15ATBFz3QEhr3hmxpYsn" crossorigin="anonymous">
Enter fullscreen mode Exit fullscreen mode

After that, we can now create HTML mark-ups in our page. So first, we create a

element with class of container and p-5 (for padding). Note that the p-5 class from Bootstrap. Inside the div, we are going have the heading, icon, form and table element which all have their respective utility classes from Bootstrap.
  • The heading contains the heading for the page, in this case the text “MyFamilyList”.
  • The icon element displays the icon provided by font awesome
  • The form takes in the name, relation and age data from the user and
  • Table displays the information on the page for the user to see. Also a pop-up alert is displayed when form is submitted and if any of the fields is omitted. This is implemented in the javascript file which we are going to dive into next. This is the full structure of our HTML page:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA==" crossorigin="anonymous" />
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/litera/bootstrap.min.css" integrity="sha384-enpDwFISL6M3ZGZ50Tjo8m65q06uLVnyvkFO3rsoW0UC15ATBFz3QEhr3hmxpYsn" crossorigin="anonymous">
</head>
<body>
  <div class="container mt-4">
    <h1 class="display-4 text-center">
      <i class="fas fa-user-friends text-info"></i> My<span class="text-info">Family</span>List</h1>
      <form id="family-form">
        <div class="form-group">
          <label for="name">Name</label>
          <input type="text" id="name" class="form-control">
        </div>
        <div class="form-group">
          <label for="relationship">Relationship</label>
          <input type="text" id="relation" class="form-control">
        </div>
        <div class="form-group">
          <label for="age">Age#</label>
          <input type="text" id="age" class="form-control">
        </div>
        <input type="submit" value="Add Member" class="btn btn-info btn-block">
      </form>
      <table class="table table-striped mt-5">
        <thead>
          <tr>
            <th>Name</th>
            <th>Relation</th>
            <th>Age#</th>
            <th></th>
          </tr>
        </thead>
        <tbody id="family-list"></tbody>
      </table>
  </div>
<script type="text/javascript" src="app.js" defer></script>
</body>
</html>

JAVASCRIPT

Our JavaScript file is going to be named app.js though you name it whatever you want. We start by defining a Member class which is going to be instantiated anytime a new family member is added via the form:

// Book Class: Represents a Book
class Member {
  constructor(name, relationship, age) {
    this.name = name;
    this.relationship = relationship;
    this.age = age;
  }

In here, we want to take the name, relationship and age as inputs and pass them into the member object.
Next, we are going to define our UI class. This contains logic which will display any all members, add a new member to the table list, display an alert, make is disappear after 3 seconds and clear field afterwards:

// UI Class: Handle UI Tasks
class UI {
  static displayMembers() {
    const members = Store.getMembers();

    members.forEach((member) => UI.addMemberToList(member));
  }

  static addMemberToList(member) {
    const list = document.querySelector('#family-list');

    const row = document.createElement('tr');

    row.innerHTML = `
      <td>${member.name}</td>
      <td>${member.relationship}</td>
      <td>${member.age}</td>
      <td><a href="#" class="btn btn-danger btn-sm delete">X</a></td>
    `;

    list.appendChild(row);
  }

  static deleteMember(el) {
    if(el.classList.contains('delete')) {
      el.parentElement.parentElement.remove();
    }
  }

  static showAlert(message, className) {
    const div = document.createElement('div');
    div.className = `alert alert-${className}`;
    div.appendChild(document.createTextNode(message));
    const container = document.querySelector('.container');
    const form = document.querySelector('#family-form');
    container.insertBefore(div, form);

    // Vanish in 3 seconds
    setTimeout(() => document.querySelector('.alert').remove(), 3000);
  }

  static clearFields() {
    document.querySelector('#name').value = '';
    document.querySelector('#relationship').value = '';
    document.querySelector('#age').value = '';
  }
}

As you can see, the methods on this class are all static. This means that you can call the methods from the UI class without having to instantiate it (use the new keyword). This class handles all UI related tasks.
Next, we define a Store class. This class is responsible for getting, adding and removing members from the browser’s localStorage which helps us persist the members permanently:

// Store Class: Handles Storage
class Store {
  static getMembers() {
    let members;
    if(localStorage.getItem('members') === null) {
      members = [];
    } else {
      members = JSON.parse(localStorage.getItem('members'));
    }

    return members;
  }

  static addMember(member) {
    const members = Store.getMembers();
    members.push(member);
    localStorage.setItem('members', JSON.stringify(members));
  }

  static removeMember(age) {
    const members = Store.getMembers();

    members.forEach((member, index) => {
      if(member.age === age) {
        members.splice(index, 1);
      }
    });

    localStorage.setItem('members', JSON.stringify(members));
  }
}

Since we can only store data as strings in localStorage, we have to covert the members array into strings to store them.
Next are the events. The first event we will look at is the 'DOMContentLoaded’ event which will get triggered when the DOM is fully loaded. We then pass one of the static UI methods as callback to display list of members on the table:

// Event: Display Books
document.addEventListener('DOMContentLoaded', UI.displayMembers);

The event is the submit event which listens for the form element with the id of #family-form to be submitted. We also provide a callback to the method which:

  • Prevent the form from being sent
  • Gets the value of the three inputs
  • Validates the inputs
  • Persists the data to localStorage
  • Adds the new member to table list
  • Displays an alert
  • Clears the fields
// Event: Add a Book
document.querySelector('#family-form').addEventListener('submit', (e) => {
  // Prevent actual submit
  e.preventDefault();

  // Get form values
  const name = document.querySelector('#name').value;
  const relationship = document.querySelector('#relationship').value;
  const age = document.querySelector('#age').value;

  // Validate
  if (name === '' || relationship === '' || age === '') {
    UI.showAlert('Please fill in all fields', 'danger');
  } else {
    // Instatiate book
    const member = new Member(name, relationship, age);

    // Add Book to UI
    UI.addMemberToList(member);

    // Add book to store
    Store.addMember(member);

    // Show success message
    UI.showAlert('Member Added', 'success');

    // Clear fields
    UI.clearFields();
  }
});

The last event is the click event which listens for a click on an element with the id of family-list. A callback function is passed in to delete a member.

// Event: Remove a Book
document.querySelector('#family-list').addEventListener('click', (e) => {
  // Remove book from UI
  UI.deleteMember(e.target);

  // Remove book from store
  Store.removeMember(e.target.parentElement.previousElementSibling.textContent);

  // Show success message
  UI.showAlert('Member Removed', 'success');
}); 

We have come to the end of the tutorial. If you liked the article and won’t mind seeing more of this, kindly share and follow. Also reach me on twitter.
P/S: If you are on the look-out for someone who can create top notch content for your blog or website, I am available. Kindly head over to my gig on Fiverr and make an order or reach me on twitter for a chat.

Discussion (2)

pic
Editor guide
Collapse
bevilaquabruno profile image
Bruno Fernando Bevilaqua

Nice post and good idea. I will do somenthing like this soon.

Btw, i found a bug in dev.to reading your post, here is the issue: github.com/forem/forem/issues/12337

Collapse
ubahthebuilder profile image
Kingsley Ubah Author

Thank you 🙏