Another Day Another Project (NiceReads in JavaScript)

Look

First of all, I have to say, this was the most difficult project I had to deal with so far at Flatiron School. We were asked to build a single page application by using a backend API that has to be created on Rails and JavaScript on the frontend. Additionally, we were asked to have a backend that includes a resource with at least one has-many relationship. And lastly, I had to figure out how to implement 3 AJAX calls between my frontend and my backend that demonstrates Client-Server Communication and covering at least 2 of Create, Read, Update, and Delete (CRUD) actions.

Setting up an API on Rails was the easiest part. — I LOVE YOU RAILS- But once I jumped on the frontend, everything started to get really difficult. I couldn’t even write a single line of code on the frontend for a while. Because we were also asked to use Object Orientation on JavaScript and that requires good designing skills. You should know how/when to connect your objects. Otherwise, you may end up getting null/undefined in your console.

All right, this is enough intro. Now let’s dive into details. Since there are lots going on I will try to keep it as simple and less confusing as I can. So basically, I created a library app that allows users to store their favorite books and perform CRUD actions on their book collection.

BACKEND

As I mentioned before, the configuration of an API on rails was really easy. All you need to do is typing rails new your_api — API command in your terminal and Rails does the rest for you.

CONTROLLERS

As a requirement, we had to handle Client/Server interaction in JSON format which means I had to set up my controllers in JSON. I will come back to JSON format again but first I want to go through my controller actions real quick. In my previous Rails project, the controllers were playing an important role in my application but this time since we were asked to build a simple SPA there is not much going on in my controllers. Basically, I do have an index, create and destroy actions in my books_controller and index and show actions in my categories_controller. That was enough for me to demonstrate CRUD actions on my app. All of my actions are rendering in JSON format. There are two ways to render your data in JSON format. In my case, since it wasn’t a large scale app, I was able to render my data by specifying JSON in my controller action as below.

But if you have more models in your app, things might get complicated. In that case, you might consider using serializers to extract your data from a service class. With the help of serializers, you can easily customize your data in JSON format. You can separate the data you want to see in JSON easily by using serializers. There is even a gem to set up service classes. It’s called FAST JSON API gem. After you installed that gem, all you need to do is typing

rails g serializer “your model”

in your terminal and then you will be all set.

PS: If you choose to extract your data from service classes, you will have to make some slight changes in your controller's actions as well. You will need to instantiate the data belongs to that particular model by using serializers as below.

class CategoriesController < ApplicationController    def show
@category = Category.find(params[:id])
render json: CategorySerializer.new(@category)
end
end

MODELS

In total, I do have 2 models. Book and Category. And as you can see below Book belongs_to Category and Category has_many books.

Book.rb & Category.rb

DB

I used sqlite3 as a DB choice in this project too. Additionally, I dumped some fake data in my seed file to test my API and see some actions on the frontend.

Seed.rb

FRONTEND

Did I tell you how hard it was? Oh man, I still don’t feel super confident about JavaScript. So if you see any mistake in my explanation please don’t mind me. I will try to drop it as simple as I can .

INDEX.HTML

I have seen 2 different approaches to this. Some people prefer to write every HTML element they need to build their app in their index.html file and they grab those elements by using querySelector and they instantiate those elements in a JavaScript class by using the class constructor. So that way, they can avoid rendering too much stuff in the DOM. I didn’t like this idea because first, this sounds hardcoding to me like if you need to implement something new, you will have to rewrite your code in your index.html. I don’t want any extra work in my life. I am a lazy programmer. And secondly, your JavaScript classes get really messy. They become hard to read. So instead, I just wrote what I needed in this file as below. The most crucial part of this file is NOT FORGETTING TO CONNECT YOUR JS FILES AT THE BOTTOM. Otherwise, you may spend tons of time for no reason in order to figure out why your application is not working.

index.html

API SERVICE CLASS

This is where I make my fetch requests to the API I built on Rails. The requests are pretty straight forward. You just gotta follow the convention. The things get a bit different though when you make a fetch request to your API when you want to modify/process data(PATCH, DELETE, AND POST). You have to make sure you specify the type of your request in your fetch. If you are planning to create new data, the method should be POST. If you are planning to update your data, it’s gotta be PATCH and so on. Normally, in a fetch request you get the response from your API first, I think we can call it raw data. And as a second step, you have to parse it into JSON format in your first .then. And then you will be able to play with that data. I mostly use that JSON formatted data in my index.js file where I manipulate the DOM. Separation of concerns is real.

ApiService.js

INDEX JS

This is where I manipulate the best friend of JavaScript. DOM. So here is the deal. Only DOM can speak JavaScript. So if you want to run some JS code in your app. You gotta go to DOM and say “ Listen DOM, I want HTML and CSS to do some stuff for me but that stuff was written in JS and I know you can speak JS. So for me, please just go to HTML and CSS and translate what I want them to do when you run my JS code.” And that’s kinda what I am doing here. I first make sure to wait until after the DOMContentLoaded event is triggered to safely execute my JS code. By creating an event listener, I keep my code from immediately firing when index.js is loaded. And inside of that event listener, I am basically instantiating my JavaScript classes. I will go into more details about my classes later on.

index.js

CategoryDropdown Class

First off, you should know that when you are working on the frontend that means you are working with HTML elements. That’s why you should consider your JS classes as a part of the HTML element. This category dropdown is a category dropdown, it’s not the category model on my backend. Make sure you understand that first. Otherwise, things will become fuzzy for you. I am saying this based on my experience. Of course, it contains your category model attributes but in fact, you are just building a dropdown menu based on the names of your categories. Also, this is where these static methods and class constructors come into play. I have one static method called categoryCollection. The good thing about these static methods is you can them directly on the class. And for the constructors, I think you can take them as a cell that contains a bit of information about your object from the beginning. And you assign that information to something called “this”. Think of “this” as a reference to the object it is inside.

CategoryDropdown.js

BookCard Class

Pretty much the same goes for my BookCard class. The important thing to note here is -it applies to my category dropdown class too- instead of passing an HTML block in my functions, I decided to render my stuff by using built-in JS methods. Like I needed to render a div element for each book card, instead of passing something like

<div class="each-book"> </div>

I used those built-in methods as below. For me, it was easier to read this way. But I do see other students choosing to render their innerHTML as I mentioned above.

let eachBookDiv = document.createElement('div');
eachBookDiv.classList.add('each-book')
BookCard.js

BookForm Class

For this class though, I had to create my form element by passing the whole HTML block in my function. Because I was having problems getting the right value from my select options when selecting a category. (event.target.value) Getting the right value was important because I do filter my books based on a category. So getting the right category id was crucial.

BookForm.js

STYLING

I did use Bootstrap and FontAwesome but additionally, I also wrote some CSS as below.

styles.css

LAST WORDS

It was very challenging and I still don’t feel super confident. There are several things involved in JavaScript. It’s a complex language. But dealing with all those problems was fun. You can check my repo over here if you want. Thanks for reading.