My First JavaScript Project

Eric Contreras Cabrera
6 min readAug 29, 2021

The JavaScript section of the Flatiron Software Engineering bootcamp was by far the hardest phase yet. Although HTML manipulation was familiar, the addition of JS made everything feel completely new. In my ignorance, I did not imagine JS to be such a powerful tool for web development as I quickly learned that literally everything on the Internet uses JS.

Brainstorming an idea for my Single Page Application (SPA) was a true challenge. The thought of developing both the frontend and backend in just two weeks made me a bit anxious; I was already imagining myself requesting an extension. Nonetheless, I was optimistic about the learning prospects that the next 14 days would bring.

Within a couple of days, I decided to create a workout tracker where a user would be able to create a workout and add exercises, grouped together by a specific muscle group. I called my JS SPA, X-ercise, and structured the project into two different entities:

  1. A Backend that would house the database, routes, models, controllers and serializers.
  2. A Frontend that would consist of HTML for structure, CSS for style, and most importantly, JavaScript for user interaction.

Creating the Backend

Before getting started, I needed to understand the relationship between my models and how they would interact. I used two models to set up my Backend:

  • Workout: has_many Exercises
  • Exercise: belongs_to Workout

Thankfully, I had used SQLITE and rails for months by now, so I felt comfortable building a quick API using Ruby on Rails. The process was simple, like building a rails app but instead of running “rails new ProjectName”, the “ — api” flag was needed to use rails as an API, which tells rails to skip the Views creation since they would not be used. The API/Database would only be storing and sending out data requested by the Frontend to be rendered. The migration files were straightforward to configure; I had my models and attributes ready to be created using the rails resource generator. The routes were also simple, since the only CRUD actions I would be using were Create, Read and Destroy. Another significant requirement included using the gem ‘active_model_serializers’ in order for my API to send a specific data structure for the JS fetch() method to understand the data properly.

SQLite Database Schema.rb

Creating the Frontend

This is where the real challenge presented itself. Despite weeks of JS lessons, my mind was still having trouble grasping the way in which JS manipulates the Document Object Mode (DOM). To add to the confusion, online resources used different and older syntax than what I learned in lecture. I ironically needed help understanding the help I was finding. Before panicking, I took time to delve into the documentation and StackOverflow and came to realize that I may not need an extension after-all. Not only did I learn to recognize and understand the differences between ES5 and ES6 syntax, I ended up developing a structure for my entire Frontend:

SRC Folder where the JS classes and CSS code would reside. It includes:

  • Exercise.js to render actions involving Exercise Class
  • ExerciseServices.js to handle all API requests for Exercise Class
  • Workout.js to render actions for Workout Class
  • WorkoutServices.js to handle all API requests for Workout Class
  • Index.js used for calling class services onto Index.html
  • Style.css used for all CSS styling for Index.html

Index.html as the one and only html that would be manipulated by JS.

New Workout Form Rendered After “New Set” Clicked
View After New Set Posted and Retrieved From Database

To get started, I thought about the class relationships and how they interact with one another on the DOM. To begin, the Workout Class constructor was used to create Workout Objects to be populated from API data. The Workout Class would also be used to create the HTML containers that would be used to append the exercise data received from the API. Another functionality that I added to the Workout Class was a button event listener for the creation of a new Exercise or deletion of an existing Exercise. The Workout Services handle API requests using JS fetch(), such as GET for fetching all Workouts, POST for creating Workouts, and DELETE for destroying a specific Workout. The following methods are the final result in the Workout Class:

  1. Constructor: includes attributes for id, title, muscle_group & exercise_sets
  2. renderWorkout(): Creates Workout List and calls Exercise Class methods to append Exercise data.
  3. renderButtonClick(): Handles rendering new Exercise Form for Exercise that belongs_to Workout & delete for current Workout.
  4. renderWorkoutCard(): Used in renderWorkout() to create a Workout container and buttons used in renderButtonClick().
  5. renderWorkoutSets(): Used in renderWorkout() to append the Workout’s Exercise Sets.
renderWorkout(), Function Within Workout.js
getWorkouts(), Function Within WorkoutServices.js

The Exercise Class was a bit easier to get started since the basic functionalities would be similar to the Workout Class, with a few additions, such as rendering an additional form to create a new workout and then appending the newly created exercise onto the DOM. The Exercise Services handle GET, POST and DELETE requests for Exercise Class. The following methods are included in the Exercise Class:

  1. Constructor: Attributes included are id, name, weight, reps, sets, muscle_group and workout_id.
  2. renderExerciseCard(): Create an exercise card ‘div’ named using current exercise with “this.name”.
  3. renderExerciseInfo(): Used to create and render the weight, reps and sets, to be appended onto renderExerciseCard().
  4. renderNewSet(newSet, containerCard): Invoked at “New Set” button click in the renderButtonClick() method from Workout Class. Takes in two arguments; an empty Exercise object called “newSet” and a containerCard. Contains button event listener for “Create New Exercise”. On click, populates newSet from user input through new Exercise Form, calls renderExerciseCard() and renderExerciseInfo() to append Exercise data for the method’s second argument, containerCard.
  5. renderNewExerciseForm(): Renders a new form for name, weight, reps and sets and “Create Set” button when called by renderNewSet().
  6. populateSetfromInput(newSet, containerCard, newForm): Called by renderNewSet, obtains user input using containerCard.querySelector(). Checks if the input is valid, if valid, populates newSet attributes with user input attributes, else there is an Alert that it cannot create an empty exercise.
enderNewSet(), Function Within Exercise.js
postSet(newSet), Function Within ExerciseServices.js

The only thing left to make the Frontend come together was the Index.js file and CSS. Index.js contains an event listener for DOMContentLoaded. This tells JS that once the page has fully loaded to fetch() all Workout and Exercise data from the API. Using the API link provided as a global variable and the Workout and Exercise Services Classes, the API data will be obtained here for use in the Workout and Exercise Classes. I also added a function to filter Workouts by a selected “muscle group” so that the page wouldn’t be cluttered by a long list of random workouts, ultimately enhancing the user experience. (This new capability added a couple extra days of testing and debugging!) Finally, the CSS file was developed alongside other Frontend components and consisted of all styling options ranging from the <body>, <button> and <div> as used within the main Index.html file.

Creating my first Single Page Application (SPA) has given me significant insight into full stack development, from learning the nuances of JavaScript to combining it with HTML and CSS for a basic web app experience. I look forward to leveraging these new skills, alongside React and Redux, in my upcoming and final Flatiron project.

View for X-ercise

--

--