Learn JavaScript by building a Random Quote Generator

In this article, we will tackle another freeCodeCamp project - building a Random Quote Generator with JavaScript. If JavaScript is your first programming language, this is a good opportunity to practice various concepts by building a small project in the language.

I assume basic familiarity with HTML (HyperText Markup Language) and CSS (Cascading StyleSheets), but you do not need to have any prior experience with JavaScript to follow this tutorial as I will explain each step.

To complete this tutorial, all you need is a modern web browser (such as Firefox or Chrome) and a working Internet connection. If you get stuck, leave a comment below, or ask a question in the chatroom and I’ll get back to you as soon as I can.

User Stories

These are the user stories for the app:

  1. I can click a button to show a random quote.
  2. I can tweet out a quote.

Getting Started

I have created a starting point for this tutorial on JSFiddle. It already contains the HTML and CSS which is used to markup and style the application.

The JavaScript pane is empty though. This is where you will write the code to fulfill the user stories.

Starting point on JSFiddle

You can also use CodePen, JSBin or whatever editor you are familiar with.

User Story #1 - Display a Random Quote

One of the most basic use cases for the JavaScript programming language is to add interactivity to a web page so that when a user does something, elements on the page will respond by performing an action.

JavaScript is used for just about everything these days, including, but not limited to, server infrastructure, desktop and mobile apps, but this is still the quickest way to put to practice what you learn.

If you look at the application in its current state, you will see that it’s really just a static page that doesn’t respond to user interaction. Clicking on the buttons does not do anything.

The page contains two buttons, the “New Quote” button which is what will be used to fetch a new quote and display it on the page, and a “Tweet” button for sharing a quote on Twitter.

The first task specifies that when the “New Quote” button is clicked, a random quote is displayed to the user.

To accomplish this, the first thing to do is to store a reference to the “New Quote” button in our JavaScript code.

If you peer into the HTML pane, you will see the markup for the “New Quote” button as follows:

<button type="button" class="new-quote button">New Quote</button>

The class attribute present is not only useful for applying styles to an element, but also for selecting elements with JavaScript.

There are many ways to select an element in JavaScript but I will show you a way that has some similarities to how you’d do it in CSS.

In CSS, you’d do this:

.classname {
  // styles go here
}

In JavaScript, you do this:

document.querySelector('.classname')

Notice that the class selector is enclosed in single quotes in the JavaScript example. You can also use double quotes.

document.querySelector(".classname")

There’s no semantic difference between the two styles. The important thing to remember is to be consistent. If using you are using single quotes or double quotes, be consistent throughout the program. I will continue to use single quotes for the remainder of this tutorial because it seems to be the preferred style for many popular JavaScript projects.

Here’s how we can select the “New Quote” button with JavaScript:

document.querySelector('.new-quote')

Next, we need to store the reference to this button in a variable. Variables in JavaScript are containers for holding different types of data structures so that you can reuse them as many times as you like. They allow us to put a label on the data in our program so that when we want to use some data we can just use the label instead of the data itself.

There are quite a few ways to create variables in JavaScript. Most beginner tutorials will show you how to create variables using the var keyword.

var name = value;

However, I will introduce you to two additional ways of creating variables in JavaScript. These involve the use of two relatively new keywords const and let were introduced in ECMAScript2015 (ES2015), also known as ES6.

const name = value;
let name = value;

These keywords were created to replace var due to its various weaknesses which made it easy to introduce bugs into a program. Although, I think it’s useful to learn how var works for historical purposes, you should declare your variables from now on with either let or const depending on how the variable will be used.

For now though, you do not need to worry about the semantic differences between let and const, just know that they are two ways to create variables in JavaScript. We will continue to use const for the remainder of this tutorial.

Variables need to have unique names. These names can consist of letters, numbers, underscores, and dollar signs. However, they cannot start with numbers (only letters, underscores, and the dollar sign).

Variable names are also case sensitive (meaning ziggy and ZIGGY are different variables) and they cannot be keywords in the language.

When you declare a variable, you need to assign a value to it. The equal to sign =, known as the assignment operator, is what is used to assign values to variables. Here’s how you declare a variable and assign a value to it in JavaScript:

const age = 40;

This variable declaration has age as its name and 40 as its value. Assignment is always from right to left. This means that all the values on the right side of the = is resolved first before the final value is assigned to the variable on the left side.

const a = 10;
const b = a; // a is resolved to 10 and before being assigned to b

Now go ahead and type this into the JavaScript pane in JSFiddle:

const newQuoteButton = document.querySelector('.new-quote');

This assigns a reference to the “New Quote” button to a new variable called newQuoteButton. Now, we can use the newQuoteButton variable anywhere in our application knowing that it will always refer to the “New Quote” button.

By the way, did you notice the presence of a semicolon (;) at the end of the variable declarations? Although not strictly necessary, the convention is to always end statements in JavaScript with a semicolon. There is no downside to doing this that I’m aware of.

Listening for events on an element

We need to detect a click on the New Quote button so that we can fetch a new random quote and display it to the user. We can do this by listening for the click event on the button

The way we listen for an event on an element is to attach the addEventListener method to the element and pass it two arguments.

Type this under the newQuoteButton variable declaration:

newQuoteButton.addEventListener('click', getQuote);

Arguments are the values between the parenthesis. The first one, click, is the event we want to listen for and the second one, getQuote, is the function that will be invoked when the click event is triggered on newQuoteButton.

A function is a block of code defined to perform a specific task. It is used to encapsulate code that we want to reuse many times so we don’t have to go through the trouble of duplicating it. This makes code easier to reason about.

The function keyword is used to declare functions in JavaScript. It is followed by the name of the function and the code that will be executed when the function is invoked between the curly braces (a.k.a the function body).

The syntax is as follows:

function name() {
  // body of function
}

The above function can be invoked or called using its name followed by parentheses, like this: name(). When you invoke a function, it executes the code defined in its body.

Sometimes, a function will have parameters. These parameters are written between the parentheses after the function name and separated by commas.

function name(param1, param2) {
  // body of function
}

You can think of parameters as placeholders for input values that will be passed to a function when it is invoked. Usually, a function that takes inputs will perform some operation on them to produce a new value.


newQuoteButton.addEventListener('click', getQuote);

Let’s return to our application. In the line of code above, we referenced getQuote as the function that needs to run when the “New Quote” button is clicked. We need to create this variable, so go ahead and insert the following code just before the newQuoteButton declaration:

function getQuote() {
  console.log("newQuoteButton was clicked");
}

Here, we created a new function, assigned it a name getQuote and, in its body, we write code to print some text to the browser console.

Go ahead and open the console in your browser (Ctrl+Shift+J / Cmd+Opt+J in Chrome and Ctrl+Shift+K / Cmd+Opt+K in Firefox). Now click the newQuote button a few times, you will see “newQuoteButton was clicked” printed to your console.

Using console.log
camera (View large version)

If you click anywhere else on the page outside the “New Quote” button, nothing happens. This is because we only listened for the click event on the button so the getQuote function is only invoked when “New Quote” is clicked.

Fetching random quotes using an API

Presently, we are logging some text to the console when the newQuote button is clicked. What we really need to do is to display a random quote to the user.

One way to do this, and this is the approach I took the first time I did this project, is to hard-code the quotes into your app and use it from there. A better approach is to get the data using an API.

There are several APIs that provide random quotes. We’ll be working with What Does Trump Thinks API which provides generic Donald Trump quotes.

To receive data from an API, you need to know the endpoint that will return the specific data that you need. You will usually find this information by taking a look at the documentation of the API you wish to use.

What Does Trump Thinks’ API documentation specifies that we use the following endpoint to get a random quote:

https://api.whatdoestrumpthink.com/api/v1/quotes/random

Let’s save this endpoint in a variable. Above the getQuote function declaration, type this:

const endpoint = 'https://api.whatdoestrumpthink.com/api/v1/quotes/random';

Next, we need to make a request to What Does Trump Thinks to grab a random quote. To do this, we will use the a mechanism in the browser called fetch. Modify the getQuote function to look like this:

function getQuote() {
  fetch(endpoint)
    .then(function (response) {
      return response.json();
    })
    .then(function (data) {
      console.log(data);
    })
    .catch(function () {
      console.log("An error occurred");
    });
}

The simplest use of fetch takes a single argument - the url to the resource you want to fetch - and returns what is known as a Promise.

The first .then() block converts the raw response into JSON (since that’s what we are expecting from What Does Trump Thinks). To use the actual data, we need to chain another .then() method and then access the data from there.

The catch block executes only if the fetch request or any of the then blocks above it throw an error. In a real-world application, you will need to handle errors properly, perhaps by showing a notification to the user, but logging text to the console would suffice for our purposes here.

Try it out. Open up your browser console and click the “New Quote” button a few times. You will see the JSON object returned by What Does Trump Think API.

Logging JSON Data to the console
camera (View large version)

If you examine the JSON object, you will see that the quote is stored in the message property and it contains a different quote each time.

The object contains some other keys such as nlp_attributes which we don’t need for this tutorial. We can access the value in the message key using dot notation like this: data.message.

If we wanted to access the value of the nlp_attributes key, we would use data.nlp_attributes.

Change the getQuote function to look like this:

function getQuote() {
  fetch(endpoint)
    .then(function (response) {
      return response.json();
    })
    .then(function (data) {
      console.log(data.message);
    })
    .catch(function () {
      console.log("An error occurred");
    });
}

Now, click the “New Quote” button a few times once more. You will see that only the quote is logged to the console, instead of the whole JSON object.

Individual quotes are printed to the console
camera (View large version)

Display the quote on the page

We will create a new function for this purpose. Type this just below the getQuote function:

function displayQuote(quote) {}

The displayQuote function is where we will wrap the code that will display the quote to the user. It takes one parameter, quote which is the quote we will display on the page.

Go ahead and write the code that will display the quote on the page:

function displayQuote(quote) {
  const quoteText = document.querySelector('.quote-text');
  quoteText.textContent = quote;
}

First, we save a reference to the element with the class of ‘quote-text’ in the quoteText variable. Next, we assign the textContent property of the quoteText element to the quote we want to display.

This replaces the contents of the quoteText element with a single text node that contains the quote received from What Does Trump Thinks.

At this point, if you click the “New Quote” button again, nothing is shown on the page. This is because, while we have defined the displayQuote function, we have not yet invoked it from anywhere and we have to do that before the code in the body of the function will be executed.

So go back to the getQuote function and change it to look like this:

function getQuote() {
  fetch(endpoint)
    .then(function (response) {
      return response.json();
    })
    .then(function (data) {
      displayQuote(data.message);
    })
    .catch(function () {
    	  console.log("An error occured");
    });
}

Now, each time a new quote is received from What Does Trump Thinks, the displayQuote function is summoned and the quote is passed to it (as input). The code we wrote in the body of displayQuote is then executed resulting in the quote being displayed on the page.

Try it out. Click the “New Quote” button a few times. You will see a new random quote displayed on the page each time.

Here’s how your code should look like at the completion of this user story:

User Story 2 - Tweet out a quote

To complete the application, we need to be able to tweet out each quote that is displayed on the page.

We already have the Tweet button on the page (actually a link which was styled to look like a button) but clicking it does not have any effect.

<a class="tweet button">Tweet</a>

This is because the link does not have an href attribute so it does not link to anywhere. Our task is to dynamically set this attribute so that it will link to Twitter’s “Share” page and pre-populate the text input with the quote we want to tweet out.

We can create another function to do this, but that’s probably overkill. Instead, let’s add that functionality to the displayQuote function:

function displayQuote(quote) {
  const quoteText = document.querySelector('.quote-text');
  quoteText.textContent = quote;

  const tweetButton = document.querySelector('.tweet');
  tweetButton.setAttribute('href', `https://twitter.com/share?text=${quote}`);
}

First, as before, we save a reference to the element we want to work with in a variable - in this case the Tweet button.

Next, we set the href attribute using the setAttribute method which takes two arguments: The attribute we want to set (href) and the value of the attribute (https://twitter.com/share?text=${quote}).

You might be wondering why I used backticks for the second argument instead of single quotes. This is because we want to interpolate the value of the quote parameter into Twitter’s share tweet URL.

To interpolate the value of a variable or expression into a string, we use Template Literals which specifies that we enclose the entire string in backticks and insert any placeholders ${expression} anywhere in the string so that the value of the expression is interpolated into the string and replaces the placeholder.

So if the value of quote is “Today, Iraq is Harvard for terrorism.” for example, ${quote} will be replaced by the value and the twitter share url becomes “https://twitter.com/share?text=Today, Iraq is Harvard for terrorism.”

This is how we are able to dynamically set the href attribute of the Tweet button to the share url that is pre-populated with any quote that is received from What Does Trump Think.

Now, click the Tweet button. This will open Twitter’s share tweet page and you will see that the contents of the text box is pre-populated with the displayed quote.

Tweet quote

One improvement we can make is to specify Donald Trump as the author of the quote in the tweet message. Change the second argument of setAttribute to this:

https://twitter.com/share?text=${quote} - Donald Trump
function displayQuote(quote) {
  const quoteText = document.querySelector('.quote-text');
  quoteText.textContent = quote;

   const tweetButton = document.querySelector('.tweet');
   tweetButton.setAttribute('href', `https://twitter.com/share?text=${quote} - Donald Trump`);
}

Now try to tweet out a quote, it should indicate Donald Trump as the author.

Tweet quote

The second user story is thus fulfilled!

One more thing…

You may notice that, if you refresh the page, no quotes are displayed and the tweet button does not work.

We can fix this easily by adding the following line to the end of the program:

getQuote();

This invokes getQuote once when the page is loaded so that a quote is fetched and displayed to the user immediately. Subsequently, new quotes will be requested and displayed on demand.


That concludes my tutorial. I hope it has helped you learn the basics of JavaScript and how you can use it to build simple web applications.

If you have a question or feedback about this tutorial, leave a comment below and I’ll respond to it as soon as possible.