DEV Community

Carl J
Carl J

Posted on • Edited on

Phase 1 Project

Here's my post about my html app.
My original idea was to do something related to medical diseases where the app would output a list of possible diseases, given a set of symptoms. I was hoping to possibly mimic WebMD or Mayo Clinic websites.
The API available to me was Lexigram Clinical NLP APIs (https://docs.lexigram.io/). Instructions to use it felt overwhelming to me and it required an API key, so I looked for another topic.
Anyway, I went with Dad Jokes. It can't get any simpler than this, right?
The api page: Dad Joke Link. I'll come back to this.

Project Start

So the project... let's look at the README.md
Some goals:

  • Design and architect features across a frontend (I'm guessing the look and feel, and style of the html page)
  • Communicate and collaborate in a technical environment (??)
  • Integrate JavaScript and an external API (k got it)
  • Debug issues in small- to medium-sized projects (sure)
  • Build and iterate on a project MVP

Actually starting the project

Like many beginners in coding, I did not know where to start. Thankfully I can use pseudo code to describe what it is I want the app to do.
Essentially, I wanted the app to:

  • Have a picture background related to the joke displayed
  • Get a random joke. Preferably when page loads.
  • Have a random button that produces a random joke.
  • Have users search for a joke, which means the background should also change to the searched term.
  • Have a search button exist.
  • Search button does something when mouse is hovering over the buttons.
  • Fetch a random joke if the search bar is empty.
  • Save the joke onto a list of favorite jokes.

.html, .css, and .js documents were made.

touch `index.html`, touch `style.css`, and `script.js`
### HTML
Enter fullscreen mode Exit fullscreen mode

When I type ! in he html document, I get a drop-down list containing pre-written set of html code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Designing the HTML and CSS, in a way is like creating an outline of what the app would do.
I know for sure that I would be using /.script.js for functions and /.style.css for page design. I did this by putting in links as below:

<!--STYLE-->
    <link rel="stylesheet" href="./style.css">
<!--END OF STYLE-->

<!--JS SCRIPT-->
    <script src="./script.js" defer></script>
<!--END OF JS SCRIPT-->
Enter fullscreen mode Exit fullscreen mode

For example I want the fonts in the app to include:

  • Gloria Hallelujah
  • Open Sans
  • Permanent Marker
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Gloria+Hallelujah&family=Open+Sans&family=Permanent+Marker&display=swap" rel="stylesheet">
Enter fullscreen mode Exit fullscreen mode

Time for the Inputs (all inside the body)

Within the <body> that was created, I had to insert a <div> and <input> within the card. And then I should be able to type some search item in the search box. Looks like so:

<body style="overflow:scroll">
    <div class="card">
        <div class="search">
            <input type="text" class="searchBar">
Enter fullscreen mode Exit fullscreen mode

But I need a button...
For this button, I decided to insert a photo search icon on it, so I used React Icons by opening up a Command Palette.

<button id="randomButton">
   <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 496 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
      <path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm33.8 161.7l80-48c11.6-6.9 24 7.7 15.4 18L343.6 180l33.6 40.3c8.7 10.4-3.9 24.8-15.4 18l-80-48c-7.7-4.7-7.7-15.9 0-20.6zm-163-30c-8.6-10.3 3.8-24.9 15.4-18l80 48c7.8 4.7 7.8 15.9 0 20.6l-80 48c-11.5 6.8-24-7.6-15.4-18l33.6-40.3-33.6-40.3zM398.9 306C390 377 329.4 432 256 432h-16c-73.4 0-134-55-142.9-126-1.2-9.5 6.3-18 15.9-18h270c9.6 0 17.1 8.4 15.9 18z">
      </path>
    </svg>
 </button>
Enter fullscreen mode Exit fullscreen mode

Next is the space/div for where the code will be displayed.

<div class="jokes">
   <h2 class="theJoke">Here comes the Joke...</h2>
   <div class="jokeList" >
      <h4>All Jokes with searched topic</h4>
   </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Style Sheet

General Header and body styling:

html {
  /* Background image? */
  background: url(https://source.unsplash.com/random/?father+child) no-repeat center center fixed;
  background-size: cover;
  /* End background image */
  height: 100%;
  overflow: hidden;
}
/* specify design of body of page */
body {
  display: flex;
  justify-content: center;
  height: 100vh;
  margin: 0;
  align-items: center;
  align-content: center;
  /* Fonts here */
  font-family: 'Open Sans', sans-serif;
  font-family: 'Permanent Marker', cursive;
  font-family: 'Gloria Hallelujah', cursive;
}
Enter fullscreen mode Exit fullscreen mode

The header is where I declared a random image to be used when the page loads.

The rest of the .css design was basic and I used the Chrome inspector to see changes in the html in real time.

Javascript

This was probably the hardest part of the project for me.
We start with the main function of joke function getJoke () {} and in this function we have our fetch and .thens.
The fetch uses the url, "https://icanhazdadjoke.com/" from the Dad Jokes API. This url apparently outputs a random Dad Joke. But let's test it! To see what kind/type/nature of data I get, I used console.log of the data output. The .thens were using arrow functions at this time. This is the code:

function getJoke () {
   fetch ("https://icanhazdadjoke.com/")
   .then ( (response) => response.json() )
   .then ( (data) => console.log(data))
}
Enter fullscreen mode Exit fullscreen mode

Output:

SyntaxError: Unexpected token < in JSON at position 0
Enter fullscreen mode Exit fullscreen mode

So we got an error!
What I realized was that I needed to add a header. As mentioned in the Dad Joke API instructions, I needed a header in the fetch to Accept: application/json. So I tried again...

function getJoke () {
   fetch ("https://icanhazdadjoke.com/", {
            headers: {
                'Accept': 'application/json'
            }
        })
   .then ( (response) => response.json() )
   .then ( (data) => console.log(data))
}
Enter fullscreen mode Exit fullscreen mode

Which produced an output:

{
  id: 'lV8hqHexHBd',
  joke: 'Why did the worker get fired from the orange juice factory? Lack of concentration.',
  status: 200
}
Enter fullscreen mode Exit fullscreen mode

Ok great! I used this for a function:

  • triggered by a button labeled "Random"
  • produces a random Dad joke
  • that is called on when a search value is blank Like so:
getRandom: function () {
        fetch("https://icanhazdadjoke.com/",
        {
            headers: {
                'Accept': 'application/json'
            }
        })
            .then((response) => response.json())
            .then((randJoke) => this.displayJoke(randJoke))
            .catch((error) => console.log("error"))
    }
Enter fullscreen mode Exit fullscreen mode

The displayJoke function would print out the joke in the section with the class name theJoke.

displayJoke: function (data) {
        const joke = data.joke;
        document.querySelector(".theJoke").innerText = joke;
    }
Enter fullscreen mode Exit fullscreen mode

But, what if I wanted a joke that included values I typed in the search box?
The Dad joke API source had instruction to use the link, "https://icanhazdadjoke.com/search?term=", in order to produce jokes with the search item. The default for "term" would list all the jokes available. Therefore, the variable "searchTerm" would be used as the input typed in the search box.

let joke = {
    getJoke: function (searchTerm) {
        fetch("https://icanhazdadjoke.com/search?term=" + searchTerm + ""
        , {
            headers: {
                'Accept': 'application/json'
            }
        })
            .then((response) => response.json())
}
Enter fullscreen mode Exit fullscreen mode

The "https://icanhazdadjoke.com/search?term=" AP, however, produced a list of jokes with the search term. So in order to display a joke, I wanted to randomize jokes in the list. I did this as a function in a .then.

getJoke: function (searchTerm) {
        fetch("https://icanhazdadjoke.com/search?term=" + searchTerm + ""
        , {
            headers: {
                'Accept': 'application/json'
            }
        })
            .then((response) => response.json())
            .then((data) => {
                let randNum = Math.floor(Math.random() * data.results.length);
                return this.displayJoke(data.results[randNum])
            })
    }
Enter fullscreen mode Exit fullscreen mode

Now when I created the function searchJoke, it would use call the function getJoke and produce a random joke from the list of searched jokes.

searchJoke: function () {
        this.getJoke(document.querySelector(".searchBar").value);
        document.querySelector(".searchBar").value = "";
    },
Enter fullscreen mode Exit fullscreen mode

I decided to put all these functions in an object so that I can call on these functions in dot format (i.e. joke.getJoke).

let joke = {
    getJoke: function (searchTerm) {
        fetch("https://icanhazdadjoke.com/search?term=" + searchTerm + ""
        , {
            headers: {
                'Accept': 'application/json'
            }
        })
            .then((response) => response.json())
            .then((data) => {
                let randNum = Math.floor(Math.random() * data.results.length);
                return this.displayJoke(data.results[randNum])

            })
    },

//get a random joke (prefer when loading page)
    getRandom: function () {
        fetch("https://icanhazdadjoke.com/",
        {
            headers: {
                'Accept': 'application/json'
            }
        })
            .then((response) => response.json())
            .then((randJoke) => this.displayJoke(randJoke))
            .catch((error) => console.log("error"))
    },
//search for a joke
    searchJoke: function () {

        this.getJoke(document.querySelector(".searchBar").value);
        document.querySelector(".searchBar").value = "";
    },

//display the joke searched
    displayJoke: function (data) {
        const joke = data.joke;
        document.querySelector(".theJoke").innerText = joke;
    }
}
Enter fullscreen mode Exit fullscreen mode

Add Event Listeners

Great! so next to do was create addEventListeners.
Created a random button and when clicked should execute getRandom function.

var randButt = document.querySelector("#randomButton")
randButt.addEventListener("click", function () {
    joke.getRandom();
});
Enter fullscreen mode Exit fullscreen mode

addEventListener for search button

var searchButt = document.querySelector(".searchButton");

//search for a joke when search button clicked or tap or selected
searchButt.addEventListener("click", function() {
    joke.searchJoke();
});
Enter fullscreen mode Exit fullscreen mode

Mouse-over & Mouse-out

When mouse cursor is over the random button, it would display the text "Random Dad Joke" and when mouse out, shows an emoji icon:

randButt.addEventListener("mouseover", function () {
    randButt.innerText = 'Random Dad Joke';
});

randButt.addEventListener("mouseout", function () {
    randButt.innerHTML = '<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 496 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm33.8 161.7l80-48c11.6-6.9 24 7.7 15.4 18L343.6 180l33.6 40.3c8.7 10.4-3.9 24.8-15.4 18l-80-48c-7.7-4.7-7.7-15.9 0-20.6zm-163-30c-8.6-10.3 3.8-24.9 15.4-18l80 48c7.8 4.7 7.8 15.9 0 20.6l-80 48c-11.5 6.8-24-7.6-15.4-18l33.6-40.3-33.6-40.3zM398.9 306C390 377 329.4 432 256 432h-16c-73.4 0-134-55-142.9-126-1.2-9.5 6.3-18 15.9-18h270c9.6 0 17.1 8.4 15.9 18z"></path></svg>';
});
Enter fullscreen mode Exit fullscreen mode

The same goes for the search button:

//change search button to solid when mouse over
searchButt.addEventListener("mouseover", function () {
    searchButt.setAttribute("style", "background-color:white;")
}, false);
//change search button back to original when mouse out
searchButt.addEventListener("mouseout", function () {
    searchButt.setAttribute("style", "background-color:#7c7c7c2b;")
}, false);
Enter fullscreen mode Exit fullscreen mode

I wanted to edit a couple things for the search box. When pressing "enter" or "return" an input, I want the search button to activate. But when the input box is empty, I want it to run the random joke function joke.getRandom().

//search for joke when press Enter key
document.querySelector(".searchBar").addEventListener("keyup", function (e) {
    if (e.key === "Enter") {
        e.preventDefault()
        document.querySelector(".searchButton").click();
    }
});
Enter fullscreen mode Exit fullscreen mode

then added this to the search button event listener

//run random joke if search bar is empty
    if (document.querySelector(".searchBar").value === null || "") 
    {
       joke.getRandom();
    }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)