Flatcoin Watchlist JS
Published: 2021-05-27 11:49:26

This App was develop as a Flatiron School JS project. I developed this app to help users create cryptocurrencies watchlists where they can see updated data from their favorite coins.

# Back End Setup:
> **Note:** You may refer to my previous Rails project for more detailed information on Rails, click the following link to find useful information about the API I'm using and more details [FlatCoin on Rails](https://dev.to/drivera53/flatcoin-on-rails-2d18).

I easily created my back end running:
```ruby
rails new js_watchlist_backend --api
```
I generated my models via `scaffold`:
```ruby
rails generate scaffold coin coin_api_id name symbol
rails generate scaffold watchlist name description
rails generate scaffold watchlistCoin coin:references watchlist:references
```
Check out my back end repository here on [GitHub](https://github.com/drivera53/js_watchlist_backend)!
# Front End:
This is a single page Application (SPA), so a basic front end JS setup will have an `index.html`, `index.css` and `index.js`.
Learning JS from scratch in one month was very challenging but after days of heavy debugging I realized that it's just a matter of understanding how to communicate with the backend API via `fetch`.

I started out by creating editing my `index.js` file.
```javascript
let editMode = false
let addWatchlist = false

let divWatchlistCollection = document.querySelector('#watchlist_collection')
const flatcoinWatchlistAdapter = new FlatcoinWatchlistAdapter(`http://127.0.0.1:3000/`)
const flatcoinCoinAdapter = new FlatcoinCoinAdapter(`http://127.0.0.1:3000/`)
const watchlistForm = new WatchlistForm
const coinlistForm = new CoinForm

// Creating a global variable for coinFormContainer
const coinFormContainer = document.getElementById("coin_form_container")
//Creating a global variable for Back to watchlist btn
const backToWatchlistBtn = document.getElementById("back_watchlist_btn")
// Creating a global variable for Watchlist Collection
const watchlistCollection = document.getElementById("watchlist_collection")
// Creating a global variable for Watchlist Form container
const watchlistFormContainer = document.getElementById("watchlist_form_container")
// Creating a global variable for Coin Collection
const coinCollection = document.getElementById("coin_collection")
// Creating a global variable for New Watchlist Btn
const newWatchlistBtn = document.getElementById("new_watchlist_btn")
// Creating a global variable for Coin Container
const coinContainer = document.getElementById("coin_form_container")
// Creating a global varial for Watch list created Confirmation Container
const confirmationContainer = document.getElementById("watchlist_created_confirmation")
// Creating a global varial for Watch list deleted Confirmation Container
const confirmationDeleteContainer = document.getElementById("watchlist_deleted_confirmation")
// Creating a global varial for Watch list updated Confirmation Container
const confirmationUpdateContainer = document.getElementById("watchlist_updated_confirmation")
// Creating a global varial for Coin Delete Confirmation
const confirmationCoinDeleteContainer = document.getElementById("coin_deleted_confirmation")
coin_created_confirmation
// Creating a global varial for Coin Create Confirmation
const confirmationCoinCreateContainer = document.getElementById("coin_created_confirmation")

// DOM
document.addEventListener("DOMContentLoaded", () => {
    watchlistForm.addCreateForm()
    flatcoinWatchlistAdapter.getWatchlists()
    watchlistForm.listenViewEditDelete()
    displayWatchlistForm()
    displayCoinCollection()
    displayGoBackWatchlists()
    handleGoBackWatchlists()
})

// Display Watchlist NEW and UPDATE form
function displayWatchlistForm() {
    newWatchlistBtn.addEventListener("click", () => {
        addWatchlist = !addWatchlist
        if (addWatchlist) {
            newWatchlistBtn.innerText = "Never mind!"
            watchlistFormContainer.style.display = "block"
            editMode = false
            // watchlistForm.addCreateForm()
        } else {
            watchlistFormContainer.style.display = "none"
            newWatchlistBtn.innerText = "Create a new Watchlist!"
        }
    })
}

// Displaying Coin Collection
function displayCoinCollection() {
    coinCollection.style.display = "none"
}

// Displaying 'Go back to Watchilists!' btn
function displayGoBackWatchlists() {
    backToWatchlistBtn.style.display = "none"
}

// 
function handleGoBackWatchlists() {
    backToWatchlistBtn.addEventListener("click", () => {
        // console.log("Go back baby")
        // Displaying Create New Watchlist
        newWatchlistBtn.style.display = "block"
        // Displaying Watchlist Collection
        watchlistCollection.style.display = "block"
        //Hiding Back to Watchlists btn
        backToWatchlistBtn.style.display = "none"
        // 
        coinContainer.style.display = "none"
        // Displaying Coins
        coinCollection.style.display = "none"
        clearCoinCollectionAndForm()

    })
}

// Testing area
// confirmationContainer.hide()
// setTimeout(function(){confirmationContainer.style.display = "none"}, 1000)

function clearCoinCollectionAndForm() {
    while (coinCollection.firstChild) {
        coinCollection.removeChild(coinCollection.firstChild)
    }
    while (coinFormContainer.firstChild) {
        coinFormContainer.removeChild(coinFormContainer.firstChild)
    }
}
```

Then I created an Adapter class for Watchlists, this handles all fetch requests.
```javascript
class FlatcoinWatchlistAdapter {
    
    constructor(baseURL) {
        this.baseURL = baseURL
    }

    // Fetch Watchlist Function
    getWatchlists() {
        fetch(this.baseURL + `watchlists`)
        .then(res => res.json())
        .then(watchlists => {
            watchlists.forEach(watchlist => {
                // console.log(watchlist)
                const w = new Watchlist(watchlist)
                //console.log(w)
                w.addToDom()
            })
        })    
    }
    // Create new Watchlist
    createWatchlist(nameInput, descriptionInput) {
        fetch(this.baseURL + `watchlists`, {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Accept": "application/json"
            },
            body: JSON.stringify({
                name: nameInput.value,
                description: descriptionInput.value
            }) 
        })
        .then(resp => {
            console.log(resp)
            return resp.json()
        })
        .then(data => {
            console.log(data.message)
            if (data.status === 201) {
                const s = new Watchlist(data.watchlist)
                s.addToDom()
                // alert(data.message)
            } else {
                alert(data.errors)
            }
            nameInput.value = ""
            descriptionInput.value = ""
            newWatchlistBtn.click()
            confirmationContainer.style.display = "block"           
            setTimeout(function(){confirmationContainer.style.display = "none"}, 1500)
        })
        .catch(err => console.error(err)) 
    }
}
```

Then a Watchlist Class.
```javascript
class Watchlist {
    static all = []

    constructor({id, name, description, created_at}) {
        this.id = id
        this.name = name
        this.description = description
        this.created_at = created_at
        Watchlist.all.push(this)    
    }

    render() {
        return(`<div class="box" id="watchlist-${this.id}" data-id=${this.id}>
                <h2>${this.name}</h2>
                <p>${this.description}</p>
                <p>${this.created_at}</p>
                <button data-action='view'>View</button>
                <button data-action='edit'>Edit</button> 
                <button data-action='delete'>Delete</button>
            </div>`
        )
    }

    addToDom() {
        divWatchlistCollection.innerHTML += this.render()
    }


}
```
And finally a WatchlistForm Class.
```javascript
class WatchlistForm {
    constructor(){
        this.handleSubmit = this.handleSubmit.bind(this)
        this.handleViewEditDelete = this.handleViewEditDelete.bind(this)
    }

    addCreateForm() {
        const watchlistFormContainer = document.getElementById("watchlist_form_container")
        const form = document.createElement('form')
        form.innerHTML = `<input id="name_input" placeholder='Name' type='text'/><br>
        <input id="description_input" placeholder='Description' type='text'/><br>
        <input id="watchlist_submit" value="Create Watchlist!" type="submit"/>`
        watchlistFormContainer.append(form)

        form.addEventListener("submit", this.handleSubmit)
    }

    handleSubmit(event) {
        event.preventDefault()
        const nameInput = event.target[0]
        const descriptionInput = event.target[1]
        if (editMode){
            flatcoinWatchlistAdapter.editWatchlist(editMode, nameInput, descriptionInput)
        } else {
            flatcoinWatchlistAdapter.createWatchlist(nameInput, descriptionInput)
        }    
    }

    listenViewEditDelete() {
        const watchlistCollection = document.getElementById("watchlist_collection")
        watchlistCollection.addEventListener("click", this.handleViewEditDelete)
    }

    handleViewEditDelete(event) {
        const div = event.target.parentElement
        console.log(div)
        const action = event.target.dataset.action
        console.log(action)
        switch (action) {
            case "delete":
                flatcoinWatchlistAdapter.deleteWatchlist(div)
                break
            case "edit":
                editMode = div
                watchlistFormContainer.style.display = "block"
                newWatchlistBtn.style.display = "none"
                // const watchiListSubmitBtn = document.getElementById("watchlist_submit")
                // watchiListSubmitBtn.value = "Update"
                document.getElementById("watchlist_submit").value = "Update"
                // Populate input
                document.getElementById('name_input').value = div.children[0].innerText
                document.getElementById('description_input').value = div.children[1].innerText
                break
            case "view":
                // Hidding Create New Watchlist
                newWatchlistBtn.style.display = "none"
                // Hidding Watchlist Collection
                watchlistCollection.style.display = "none"
                //Displaying Back to Watchlists btn
                backToWatchlistBtn.style.display = "block"
                // Displaying Coin Form
                // const coinlistForm = new CoinForm
                coinlistForm.addCreateForm(div.children[0].innerText, div.dataset.id)
                // const coinContainer = document.getElementById("coin_form_container")
                coinContainer.style.display = "block"
                // Displaying Coins
                coinCollection.style.display = "block"
                console.log(div)
                // const flatcoinCoinAdapter = new FlatcoinCoinAdapter(`http://127.0.0.1:3000/`)
                flatcoinCoinAdapter.getCoinlist(div)
                // Adding an event listener for delete
                coinlistForm.listenDelete()
            default:
                break
        }
    }
}
```

The logic for Coin object is the same as the watchlist, you may check out my front end repository here on [GitHub](https://github.com/drivera53/js_watchlist) for the full code.
Check out a quick [YouTube](https://www.youtube.com/watch?v=-ReVeWpl7uE&t=22s) video of my application.