Howdy Folks, In this tutorial, you will learn how to build a Random Dad Joke Generator using Javascript, HTML, and CSS. It's a simple application that fetches a new Dad joke each time when you hit a button, and it displays it in the browser. You can also tweet it too!!

Before jumping right in first take a look at the demo here on Codepen - Random Quote Generator Demo

You can download the completed project from GitHub - Random Joke Generator

Or you can get the final code at the end of each section too...

Prerequisites

I assume you are already familiar with basic Javascript. And you should have a decent understanding of HTML, CSS, and JSON. You should also know how to make a request to an API using fetch(). Knowledge about Promises is also expected.

But wait, If you don't know some of them or any of them, don't worry, just continue. I will try my best to keep this tutorial simple.

Besides the things above mentioned, you will need:

  • Internet Connection, for making the API request.
  • Twitter Account, to test things out. If you had one, please Sign In. If you didn't have one, then create one and Sign In.
  • Then, a Modern Web browser(such as Firefox or Chrome)
  • Finally, a Text Editor.

I am going to use "visual studio code" as my text editor. You are free to use whatever code editor you like. And finally, make sure you have installed Live Server by Ritwick Dey in visual studio code. If you don't have Live Server installed, then:

  • Open visual studio code
  • Goto Extensions tab (Ctrl + Shift + X)
  • Search for "Live Server" by Ritwick Dey
  • Then Install it

But wait, As usual, How we are going to build this thing?

Breaking Down the Logic

The logic is quite simple:

 

logic breakdown

Our layout will look something like above. The main items we have here are:

  • .joke-text paragraph. Here's where we will be displaying our joke text.
  • .new-joke-btn button.
  • .tweet-btn link. This is actually an <a> tag.

When the user clicks on the .new-joke-btn button, we should make an API request, and fetch a joke, then display it on the screen. We are going to use icanhazdadjoke API for getting some Dad Jokes.

Then, If the user clicked on the .tweet-btn link, tweet the joke. If some error happened, then display an error message.

That's it. That's all that we want to do. Now let's get started...

Initial Setups

Create a folder structure similar to below:

folder structure

  • First, create the root folder which holds everything and name it as "Random Joke Generator" or anything you like.
  • Then open this folder inside visual studio code.
  • Then directly inside this root folder, create the following files:
    • index.html - this is going to hold all of our HTML.
    • styles.css - this will hold all of our CSS styles.
    • script.js - this is the most important file. This will hold all of our Javascript logic.

That's it. Now you should have a folder structure similar to above. Now the HTML part...

HTML

Open "index.html" and type the following:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="./styles.css" />
    <title>Random Joke Generator</title>
  </head>
  <body>
  
      <!-- container -->
    
    <script type="text/javascript" src="./script.js"></script>
  </body>
</html>

That's our boilerplate code. There's nothing special in there. We are giving some <meta> tags, one for setting the charset, and one for the viewport. They are not required here. But always using them is a good practice. Then we are linking our "styles.css" file. ./ means from within the current directory (we are giving the relative path). Then we give the title. Before the ending </body> tag, we are linking our "script.js" file. That's it.

Now below this '<!-- container -->' comment, type the following:

<div class="container">
        <!-- heading -->
        <h1>Dad Jokes 😆</h1>
        <!-- joke text -->
        <p class="joke-text">
          Joke Text Goes In Here...
        </p>
        <!-- buttons -->
        <div class="buttons">
          <!-- .new-joke Button -->
          <button class="btn new-joke-btn">New Joke</button>
          <!-- .tweet Button (actually a link). No href initially -->
          <a href="" class="btn tweet-btn" target="_blank" rel="noopener noreferrer">Tweet!!</a>
        </div>
      </div>

Here, we have a .container div, which acts as a wrapper. Inside that there is a:

  • <h1> - which holds the title "Dad Jokes 😆".
  • <p> with .joke-text class. Initially put some dummy text in there.
  • <div> with .buttons class. This holds two things:
    • <button> with class .btn and .new-joke-btn.
    • <a> link with class .btn and .tweet-btn. Note that this had no href attribute initially. We will add it later. Then inside <a>, we have the attributes:
      •  target="_blank", which opens the tweet link in a new tab.
      • rel="noopener noreferrer", for the security purposes.

That's it our HTML part is done. Here is the final code for the "index.html" file. Make sure the code you typed up to this point inside the "index.html" file is exactly like the following:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="./styles.css" />
    <title>Random Joke Generator</title>
  </head>
  <body>
  
      <!-- container -->
      <div class="container">
        <!-- heading -->
        <h1>Dad Jokes 😆</h1>
        <!-- joke text -->
        <p class="joke-text">
          Joke Text Goes In Here...
        </p>
        <!-- buttons -->
        <div class="buttons">
          <!-- .new-joke Button -->
          <button class="btn new-joke-btn">New Joke</button>
          <!-- .tweet Button (actually a link). No href initially -->
          <a href="" class="btn tweet-btn" target="_blank" rel="noopener noreferrer">Tweet!!</a>
        </div>
      </div>
      
    
    <script type="text/javascript" src="./script.js"></script>
  </body>
</html>

Now Open it with Live Server by right-clicking on the "index.html" file (inside visual studio code), then scroll down and click on the "Open with Live Server" option and take a look at it in the browser. You would see something like this:

html only

You will not see any style now. Because we only linked the "styles.css" file but didn't write any CSS styles. So now let's do that. Let's add some styles...

CSS

Open the "styles.css" file you created and type the following:

/* common styles */
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

a {
  color: #111;
  text-decoration: none;
}

.btn {
  padding: 10px 20px; /* top-bottom left-right */
  margin: 0 5px; /* top-bottom left-right */
  font-size: 0.99rem;
  border-radius: 3px;
  outline: none;
  border: none;
  color: #fff;
  background-color: blue; /* default color */
}

.btn:hover {
  cursor: pointer; /* hand symbol */
}

/* body */
body {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background-color: #6B2A7E;
  font-family: sans-serif;
  display: flex;
  justify-content: center; /* horizontally center */
  align-items: center; /* vertically center */
  text-align: center;
}

/* container */
.container {
  width: 450px;
  padding: 50px 20px; /* top-bottom left-right */
  background-color: #fff;
  border-radius: 5px;
}

/* h1 */
h1 {
  font-size: 1.1rem;
  color: #888;
  margin-bottom: 20px;
  text-decoration: underline;
}

/* .joke-text */
.joke-text {
  font-size: 1.8rem;
  margin-bottom: 30px;
  font-family: monospace;
}

/* .new-joke-btn */
.new-joke-btn {
  background-color: #FF0000;
}

/* .tweet-btn link */
.tweet-btn {
  background-color: #00ACEE;
}

I am not going to explain the CSS styles. Rather I challenge you to decode this on your own. The styles are very basic, nothing complicated. That's why I am not going to explain it. If you got stuck at some point, then feel free to comment below, I am always here to help you.

Now If you take a look at the browser, you will see the page with the styles 😍.

css only

Our application looks nice, but it wouldn't work. So let's add the functionalities using Javascript.

Javascript

Before writing any Javascript code, Open the "script.js" file and copy the following comments first, because they will help you to put the codes in the proper places. Yes, you can put your code wherever you like, but I like to do everything in the order.

So copy the following comments inside "script.js" file:

// grab a reference for necessary HTML elements


// add 'click' eventListener to .new-joke-btn


// getJoke() function definition

Once again, I repeat the logic:

  • When the user clicks on the .new-joke-btn button, we need to make an API request, right?.
  • After that, when we get the joke, we need to display it on the .joke-text paragraph. 
  • If we got some error, then display an error message on the .joke-text paragraph instead of any joke.
  • And if the user clicked on the .tweet-btn link, then tweet the joke.

So to do all these things, we need some reference for all the HTML elements we need to work with, right? That's what we are going to do next.

Grab the necessary elements

We are going to grab a reference for all the necessary HTML elements from the DOM. We need the .joke-text paragraph, .new-joke-btn, and .tweet-btn link. So let's grab them and store them inside the corresponding constants.

Type this below '// grab a reference for necessary HTML elements' comment in the "script.js" file:

// .joke-text
const jokeText = document.querySelector('.joke-text');
// .new-joke-btn 
const newJokeBtn = document.querySelector('.new-joke-btn');
// .tweet-btn (link)
const tweetBtn = document.querySelector('.tweet-btn');

The next thing we need to do is that we want to know if someone had clicked on the .new-joke-btn button or not. We can do it by adding a 'click' event listener to that button.

Add an EventListener

Type the following code below '// add 'click' eventListener to .new-joke-btn' comment:

newJokeBtn.addEventListener('click', getJoke);

// immediately call getJoke()
getJoke();

When the user clicks on the .new-joke-btn, we activate a function called getJoke(). Then in the next line, we called it immediately to run it as soon as the user opened the web browser.

This function is going to do all the things like making an API request and blah blah blah... But We hadn't created it yet. We only called it. So let's create it.

getJoke() function

Type the following code below '// getJoke() function definition' comment:

function getJoke() {
  // make an API request to https://icanhazdadjoke.com/'
  fetch('https://icanhazdadjoke.com/', {
    headers: {
      'Accept': 'application/json'
    }
  }).then(function(response) {
    /* convert Stringified JSON response to Javascript Object */
    return response.json();
  }).then(function(data) {
    /* replace innerText of .joke-text with data.joke */
    // extract the joke text
    const joke = data.joke;
    // do the replacement
    jokeText.innerText = joke;

    /* make the tweetBtn(.tweet-btn link) work by setting href */
    // create tweet link with joke
    const tweetLink = `https://twitter.com/share?text=${joke}`;
    // set the href
    tweetBtn.setAttribute('href', tweetLink);
  }).catch(function(error) {
    // if some error occured
    jokeText.innerText = 'Oops! Some error happened :(';
    // removes the old href from .tweet-btn if found any
    tweetBtn.removeAttribute('href');
    // console log the error
    console.log(error);
  });
}

Whoa, Whoa!! A lot is going in there! Don't worry let's break it down. Keep an eye on your code and follow the explanation. 

The explanation for the above code:

  • Inside our getJoke() function, we are using fetch() with some headers to perform the API request. The fetch() will take some time to finish. Because, it would always take some time to perform the API requests and get the response back, right? We are dealing with Javascript Promises here.
  • So after the request has been finished successfully, the callback function inside the first .then() will get activated. The callback function automatically gets the response as its first argument. But note one thing, that the response we get back from the API will not be in the JSON format. But we need JSON Data! So after converting it into JSON by doing response.json() we then return it to the next .then().

Now our JSON data at this point looks something like this:

json data

  • Inside the next .then() we accept this converted JSON data. But we don't want all of the data inside this JSON. We only need the "joke". That's what we are doing inside the callback function of the .then(). We extract the joke from data by doing data.joke:

extracting joke from data

  • Then we set the innerText of .joke-text with the current joke data:

setting innerText

  • Now our .new-joke-btn is ready! So let's make the .tweet-btn link work by giving a valid href attribute. Do you know how the link looks like when we "tweet" on Twitter? It should look something like below. Try to open it. I hope you already had a Twitter account and you are already signed in:

https://twitter.com/share?text=hello

  • The above link is for making a tweet with the word "hello". So if we want to make a tweet with our joke, then we can do something like this:

joke link 

  • Note, here we are using template literals. This is not single quotes ' ' or double quotes " ", here we are using `` backticks. And whatever variable we put inside ${}, will get replaced with its corresponding value. Here we are putting our joke variable inside the ${}. So our final link will be like this - https://twitter.com/share?text=TheJokeTextGoesInHere
  • Then after setting the href to tweetBtn, as the final step, we are adding a .catch() statement at the end. This will handle the error if something goes wrong and displays an error message and also console.log() the error.

catch statement

That's it!!!

Hooray, we had reached the end :). Now our application will work perfectly :) Hey go check it out in the browser...

Here is the final code for the "script.js" file. Make sure the code you typed up to this point inside the "script.js" is exactly like the following:

// grab a reference for necessary HTML elements
// .joke-text
const jokeText = document.querySelector('.joke-text');
// .new-joke-btn 
const newJokeBtn = document.querySelector('.new-joke-btn');
// .tweet-btn (link)
const tweetBtn = document.querySelector('.tweet-btn');

// add 'click' eventListener to .new-joke-btn
newJokeBtn.addEventListener('click', getJoke);

// immediately call getJoke()
getJoke();

// getJoke() function definition
function getJoke() {
  // make an API request to https://icanhazdadjoke.com/'
  fetch('https://icanhazdadjoke.com/', {
    headers: {
      'Accept': 'application/json'
    }
  }).then(function(response) {
    /* convert Stringified JSON response to Javascript Object */
    return response.json();
  }).then(function(data) {
    /* replace innerText of .joke-text with data.joke */
    // extract the joke text
    const joke = data.joke;
    // do the replacement
    jokeText.innerText = joke;

    /* make the tweetBtn(.tweet-btn link) work by setting href */
    // create tweet link with joke
    const tweetLink = `https://twitter.com/share?text=${joke}`;
    // set the href
    tweetBtn.setAttribute('href', tweetLink);
  }).catch(function(error) {
    // if some error occured
    jokeText.innerText = 'Oops! Some error happened :(';
    // removes the old href from .tweet-btn if found any
    tweetBtn.removeAttribute('href');
    // console log the error
    console.log(error);
  });
}

Wrapping Up

I hope you enjoyed this tutorial. If you had any doubts, then please comment them below. Thank you ;)