DEV Community

JosetteTGarcia
JosetteTGarcia

Posted on

The Habit Tracker

Hello, Dev Community!

This week I completed one of my first projects for FlatIron school. The focus of this project was to solidify beginning concepts in javascript, CSS, HTML, and API. In this post, I will cover the following topics regarding this project:

  • The concepts I came up with to fulfill the requirements of the program and build an app I would actually use
  • The challenges I’ve faced as a beginner and how I was able to navigate through these (createDocumentFragment(), loops, form submission to object)
  • Reflection and improvements

The Habit Tracker App

Why did I create this app? This app is inspired by Atomic Habits by James Clear. Clear's philosophy, as well as this app's, is to break down goals into smaller daily habits that when completed consistently, can allow individuals to reach larger accomplishments.
This app makes it simple and starts with just 30 days and the three rewards the user promises themself. Tracking your goals should be the least hardest thing about reaching them.

For a user, this app works by submitting a form with your goal and habit information. Once submitted, a “goal card” will render to the right where the user can come and check a box for each day they completed the habit they are building. If they are done tracking their goal, they can delete it with the “Delete” button on each card.

If they need extra motivation, they can click the “Click Me for Motivation” button which will pop up a James Clear Quote. They can even click the “Tips Video” link in the navigation bar to watch a video summarizing Atomic Habits.
How it Works:

This project includes [3] main features:

  • Form for entering your goals to create a goal card
  • The ability to check off each day of your goals
  • Local JSON-server to persist the goal card through refreshes
  • Connection to James Clear Quotes API for motivation

I’d like to break down two of them-

The Goal Form:

After the initial steps of creating a CSS grid styling for the app, I wanted to focus my first javascript efforts on the form submission of the goal. Submission of this form is what would trigger the new goal card to populate and basically kicks starts many of the functions of the app.

In order to target the inputs of a form, I had to first target the “submit” event from the “Add New Goal” button. I used a global QuerySelector and appended an event listener that listened for the “submit” event and started the HandleFormSubmit function. The HandleFormSubmit’s function’s main job was to set the values from into a goalObject and kickstart the function that creates our cards and the function that saves our object to the local JSON server.

Image description

An interesting lesson here was that we are listening for the “submit”, specifically because it is a form. Even though we are “clicking” the button to submit our form, the submit event is tied to the form and ensures our values are pulled. It’s intended for when we expect to return information from an input vs just trigger another action.

Image description

Appending the 30 days checkboxes to the goal card

This was the hardest part of my code to figure out. Instead of having to repeat 30 lines of code in the HTML, I thought to include a loop that would append the 30 lines of code to the new card after it’s been created. To the user, this looks instant.
To do this, I used createDocumentFragment(), which I learned is a quicker, and cleaner solution when attaching multiple elements to the DOM (resource blog from another DEV blogger).
For others who may plan to do something similar, here is the process I’d follow:

  1. Set a variable to document.createDocumentFragment();
  2. Within your function that creates the HTML for your card, set a for loop to the amount of times you need your code to repeat
  3. Add a new variable that appends createElement() to the original, Fragment variable
  4. Set the second variable inner.html to your needed code
  5. Outside of the for loop, you will use appendChild() to append your original variable to the node

Essentially, once the new card from our form submission is created, we append the document fragment to this newly created HTML section. The document fragment calls our element creator and the for loop.
For styling reasons, I included an if-else statement to add a break in certain iterations.

Here is a sample for anyone who would like to recreate:

const containerForFragment = document.createDocumentFragment();

for (let i = 1; i < 31; i++) {  
    let newElement = containerForFragment.appendChild(document.createElement("li"));
    newElement.innerHTML = "";
    if (i == 10|| i == 20 || i == 30) {
    newElement.innerHTML = `
    <label>
      <input type="checkbox" id = "checkbox" />  
      <span> </span>
      <text> ${i} Days completed! Collect a reward! </text>
      </label>
    <br>
    ` 
    } else {
    newElement.innerHTML = `
    <label>
      <input type="checkbox" id = "checkbox" />
      <span> </span> &nbsp;
    </label>
    ` 
    }
  };
  // step 3. slap it on the DOM!

  newCard.querySelector("#NodeID").appendChild(containerForFragment);
Enter fullscreen mode Exit fullscreen mode

I learned a lot through this project and feel like I've built a product I would use on my own. If I were to continue to build on this application, I would host my server so I could then create user accounts and data can persist for users other than myself. I'd also like to eventually create the ability to track progress over a longer period of time.

Example. If a user only completes 15 out of the 30 days of the habit, we can save this data, refresh the 30 days, and track their improvement month to month.

Thanks for your time! I would love to hear your feedback regarding this application or any of the topics discussed.

If you would like to check out the code for my project you are welcome to do so.

Top comments (0)