FLATIRON SCHOOL - JAVASCRIPT & RAILS PROJECT
Tags: javascript, webdev, beginners, rails
Published: 2021-10-11 20:42:27

## The Project

This is the fourth and penultimate project we had to do in Flatiron's software engineering programme. The requirements of this project was to build a single page web application with a JS, HTML and CSS frontend, and a rails API backend. The application was supposed to have a least three AJAX calls, one has-many relationship on the backend and all communication between client and server was to be handled asynchronously in JSON format.

## My Application
The application I made is called Yard Sale. It is an app that takes a real world yard sale online by allowing users to put up items they own, whether new or used, online for sale. The app has full CRUD (create, read, update and delete) functionality and also has extra features that allow users to search for items by name and also hide items on the page.

![Homepage of Yard Sale app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dto93ae5jihq4hb0n05r.JPG)

## Making The App

### The Backend
I built the backend of the application first. This was fairly quick and easy to do as I used the rails scaffold generator to generate the models, migrations and all other needed files. There is a slight difference in the commands used to generate a new rails app and a rails api. The command used for the rails api is `rails new [app_name] --api`. The api flag at the end tells the system the app is strictly being used as an api so it does things such as: 1. let your ApplicationController inherit from ActionController::API instead of ActionController::Base.
2. configure your generators so they skip generating unnecessary files such as views, helpers and assets.

I also used an ActiveModel Serializer to serialize the data and select only the information I wanted to display. Finally, I added model validations to control what data I wanted to be entered into forms on the frontend. 

### The Frontend 
Most of the work I did came in the front end. First, I implemented separation of concerns concept by separating my JavaScript files into four different folders which each contained code that was exclusive to a unique purpose. The code was also organized into classes following Object Oriented Programming principles as shown in the code snippet below.

![code snippet showing object orientation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3zyc9mu7zzxs0x084qud.jpg)

I used `fetch()` to make all my AJAX calls with the appropriate method included. I also took advantage of template literals( literals delimited with backticks (`), which allow embedded expressions called substitutions)  to sometimes output HMTL in my JS classes as shown below.

![code snippet showing use of template literals](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5wa7gkc3mimncpdy4ss.jpg)

Another concept I took great advantage of was the use of destructuring assignment when creating objects in my application. 

## Challenges
The main challenge I encountered during the making of the app was how to implement the search feature. I am going to detail how I did it below step by step.
1. The first step was to create a form in my html file where users can type in search terms.
`<form id="search-items">
       <input type="text" placeholder="Search item... "/>
 </form>`

2. Next, we add an event listener to the input. But before that, it is always advisable to assign that input to a variable to make our code more readable and also in case we need to reuse that input.

3. We grab the input by first finding the particular form using `document.forms[id]` and then using the query selector to grab the input. In the case of our form above, this will be :
`const [variable_name] = document.forms["search-items"].querySelector("input");`

4. We now attach an event listener to the input we have grabbed. The event listener takes in two arguments: the name of the event and the callback function we want to run when the event occurs.
`[variable_name].addEventListener("keyup", searchItem);`
"keyup" here is the type of event and "searchItem" is the callback function.

5. We now have to define this callback function `function searchItem(e){
}`.
i. We set a variable to the value of the input and convert it to lowercase to avoid any case issues when users search for an item.
`const [var] = e.target.value.toLowerCase();`
ii. We have to set a variable to the "li" tag which contains the item assuming they are in a list.
`const [var_name] = parentNodeofList.getElementsByTagName("li");`
iii. This will yield a collection so we use the `Array.from` method to generate an array from this collection and use `forEach` to iterate through each element.
`Array.from(var_name).forEach(element =>{})`
iv. At this point, our searchItem function looks like this:
`function searchItem(e){
    const [var] = e.target.value.toLowerCase();
    const [var_name] = parentNodeofList.getElementsByTagName("li");
   Array.from(var_name).forEach(element =>{})
}`
v. Now we need to grab the content of the exact text that we will be matching the user input against. In the case of my app, this was stored in an "li" element with this classname of "name". We set it to a variable as usual for reusability.
`const [text] = element.querySelector(".name").textContent;`
vi. Our next step is to compare the user input with the text content. We do this by determining whether the user-entered text is found anywhere within the name of the items in the database in the case of my app. This is done using the `indexOf` method. This method returns -1 if the object is not found in the array. So we say if the indexOf method does not return -1, the item should be displayed on the page. Else, the item should not be displayed.
`if(text.toLowerCase().indexOf(var) != -1) {
               element.style.display = "block";
            }
            else{
                element.style.display = "none"
            }`

vii. Our full searchItem function now looks like this:
`function searchItem(e){
    const [var] = e.target.value.toLowerCase();
    const [var_name] = parentNodeofList.getElementsByTagName("li");
   Array.from(var_name).forEach(element =>{
if(text.toLowerCase().indexOf(var) != -1) {
               element.style.display = "block";
            }
            else{
                element.style.display = "none"
            }
})
}`


## Conclusion
This project has definitely been my favorite to work so far because I finally got to build an application which looked and felt like the web apps we use everyday. The whole process thought will never have been possible without the guidance of our very able cohort lead Candice, so I would like to thank her. Overall, this was a very fulfilling project and I learnt so much building it.