How I planned and built my first JavaScript project

As part of my freeCodeCamp Front End Development certificate, I was asked to build a random quote generator which met the following requirements:

  • User can click a button to see a new quote
  • User can click a button to tweet out a quote

Since I want to add this project to my portfolio, I thought it would be useful to explain, in detail, how I approached the process.

Brainstorming / Project planning

Before I start coding, I like to step back and think about what I’m about to build. Seems obvious, but sometimes it can be tempting to jump right into coding! For this project, I determined that I would need these main components:

  • A web page
  • Quotes, to check that the code is working (at least 10, preferably more)
  • JavaScript to select quotes at random and add them to the web page (of course, there are many ways to accomplish this, but freeCodeCamp put this project right after the JavaScript lessons, and I wanted to get some practice using what I had just learned).
  • The ability to tweet the quote that appears on the web page

I did some initial planning for each of these components to make my process easier and faster.

The web page

I sketched out my idea of what a random quote machine should look like. I knew I wanted the focus to be on the text of the quote, not on other design details, so I planned to use a large, readable font with sufficient contrast to the background. Normally, I wouldn’t think too much about fonts this early in the design process, but for some reason, the Montserrat + Open Sans combo was calling to me, so I wrote it down. My initial sketches looked like this:

Image description: Two quote machine sketches, one of a desktop view and one of a mobile view. The desktop view has large, left-aligned text with a right-aligned quote attribution and right-aligned buttons. The mobile view is all center-aligned. Notes in the margins indicate that Montserrat and Open Sans fonts will be used, and the page will show a dark background with a white box, which will hold the quote, attribution, and buttons.

I figured this simple design would be easy enough to build using Bootstrap, and I could add my own touches (changing the default colors and fonts) to reflect my design sensibilities.

The quotes

I thought about using an API rather than researching and gathering my own quotes, but I didn’t like the idea of potentially unsavory/offensive quotes coming up for my users. And, since one of the user requirements was the ability to tweet out the quotes that come up, I needed to ensure these quotes were shorter than 140 characters, preferably including their attributions.

The code

Since I’m still relatively new to building things from scratch in JS, I tend to think in English and then “translate” to JavaScript. Here’s what I came up with:

  • Store quotes in an array
  • Generate a random number, which is less than or equal to the array length
  • Use that random number to select a quote from the array and place it in a designated area on the web page

Now that I had done this initial thinking, I had a clear roadmap for my project:

  • Build a simple page using Bootstrap
  • Find and organize quotes that are shorter than 140 characters (including attribution)
  • Write my code
  • Test and evaluate the project

Building the web page

Before I started to build my page, I made some higher-fidelity mockups to ensure my original vision would look good on a variety of screens — you can see one of them below:

I made this first one in Canva because it’s a simple and fast tool, and then made the rest in Sketch once I was satisfied with this one.

Note: If the main goal of this project were the visual design, I would have made a typography scale and style guide. However, I wanted to spend more time on the JavaScript for this particular project.

Then, I took a real quote that I planned to put in my project and built out the site in Codepen — you can see the code here. I like how easy it is to add Bootstrap and JS while prototyping, and the export feature lets me easily move the project over to my Github account once it’s done.

Image description: a screenshot of my project’s Codepen, with the HTML/CSS on the left and a preview on the right.

You might have noticed that the final page looks a little different from my wireframes. As it turns out, the right-aligned quote attribution and buttons looked strange with a longer author name. Plus, I didn’t like the way the buttons jumped from the right of the box to the center as the screen was being resized. I moved the attribution to line up with the text, and put the buttons in the center.

Collecting and organizing quotes

As I mentioned previously, I needed a number of quotes that could fit into a tweet. I thought about keeping the quotes even shorter so I could add a link to my page or Twitter account, but decided to prioritize finding good short quotes over finding short quotes that leave room for a linkback.

The easiest way for me to assemble and check for character counts was to create a Google Spreadsheet which you can view here. I set up a column for quotes and another for their attributions, and wrote a simple formula to count the number of total characters:

=SUM(len(A1) + len(B1))

I then applied conditional formatting to the column so that the cells would turn red if the character count exceeded 139 (because I knew I’d need a space between the end of the quote and the start of the attribution!).

Image description: a screenshot of the Google Spreadsheet containing the quotes I used for this project

My goal was to gather at least 10 quotes, so I would be able to see if my code was working once I added it to my Codepen. I have 20 there now, and am taking suggestions for any that you think would fit with my theme. :-)

Writing the code

Now, for the fun part! Time to walk through the process of how I wrote the code for this project. I’ll break it down by the steps I listed during the “Brainstorming” section:

Store quotes in an array

You’ll notice from my wireframe and final web page that the quotes and attributions have different font sizes and alignments. This means I need to be able to access and manipulate the quotes and attributions separately — but I need to make sure the quotes and attributions are always matched correctly. The best way to do this is to treat each quote as an Object, with two properties: the content of the quote, and the author or source of that quote. My array looks like this:

var quotes = [
{content: 'quote1', source: 'author1'}, {content: 'quote2', source: 'author2'}, {content: 'quote3', source: 'author3'} … ]

Next, I wrote my function, which needed to:

Generate a random number, which is less than or equal to the array length

The purpose of generating a random number is to use it to select the nth-indexed object from my quotes array. So if I have 20 quotes in my array, I want a number between 0 (corresponding to quote1, source1) and 19 (corresponding to quote20, source20).

To do this, I used Math.random() to generate a number between 0 and .99, multiplied that by quotes.length + 1 (remember, because arrays are 0-indexed, quote + source #20 are actually going to be at index 21), then used Math.floor() to round the result down to the nearest integer. That gives us a random number between 1 and however many quotes are stored in our array. I stored that in a variable called randomNumber.

var randomNumber = Math.floor(Math.random() * quotes.length + 1);

Now we need to:

Use that random number to select a quote from the array and place it in a designated area on the web page

Remember how I said I needed to work with the quote text and attributions separately? All we have to do is store them in two separate variables!

var quoteContent = quotes[randomNumber].content;
var quoteSource = quotes[randomNumber].source;

We’re telling the function to look at the array called quotes and look at the object in the index equal to randomNumber. For quoteContent we want to store the value of content at that index, and for quoteSource we want to store the value of source.

Finally, we’re going to take those values and put them on the web page I built. We can do that with this bit of code:

document.getElementById("quote-text").innerHTML = quoteContent;
document.getElementById("quote-source").innerHTML = quoteSource;

If you look at my HTML, you’ll see I’ve designated a place for the quotes and attributions by assigning the id of #quote-text and #quote-source, respectively. This code uses the innerHTML property to change the content of an element that has been assigned the id in parenthesis. Note that the id is written as “quote-text” rather than #quote-text.

And that’s it! If we put that all together, we have:

function getQuote() {
var randomNumber = Math.floor(Math.random() * quotes.length + 1);
var quoteContent = quotes[randomNumber].content;
var quoteSource = quotes[randomNumber].source;
document.getElementById(“quote-text”).innerHTML = quoteContent;
document.getElementById(“quote-source”).innerHTML = quoteSource;
};

So, let’s talk through this in order:

In the variable called randomNumber, we generate and store a random number. To do that, we use Math.random(), and let’s say we get 0.83. We multiply that by quotes.length, which has 10 quotes stored in it. 0.83 * 10 = 8.3. We add 1 to get 9.3, and then Math.floor() rounds that down to 9 for us. Now,

var randomNumber = 9

… so we will be working with the quote at index 9 in the quotes array. Index 9 in our array contains:

{content: “A political struggle that does not have women at the heart of it, above it, below it, and within it is no struggle at all.”, source: “-Arundhati Roy”}

For our next two lines of code, we can substitute:

var quoteContent = “A political struggle that does not have women at the heart of it, above it, below it, and within it is no struggle at all.”;
var quoteSource = “-Arundhati Roy”;

Finally, when it’s time to replace the contents of our #quote-text and #quote-source elements, we’ll have

document.getElementById("quote-text").innerHTML = "A political struggle that does not have women at the heart of it, above it, below it, and within it is no struggle at all.";
document.getElementById("quote-source").innerHTML = "-Arundhati Roy";

And we end up with this:

Now, we need something to tell the browser to perform this function. The HTML onclick event attribute makes that easy for us. All we have to do is add

onclick = "getQuote()"

to the button I’ve created in the HTML of the web page:

<button type="button" onClick="getQuote();" class="btn btn-primary" id=”new-quote”>New Quote</button>

Now, whenever someone clicks on the New Quote button, the function will generate a new random number and use that to place a quote and attribution in the appropriate parts of the page.

But we’re still missing something:

The ability to tweet the quote that appears on the web page

Twitter provides instructions for creating a button that will generate a pre-populated tweet for users. For example, a link with the following href:

href="https://twitter.com/intent/tweet?text=Hello%20world"

…will generate a tweet that says Hello world — so we need a way to replace the characters after the text= part of that href attribute with our quote.

For the sake of consistency, I could have figured out to do this with vanilla JavaScript… but there were clear instructions for accomplishing this with jQuery, so why reinvent the wheel? It’s just a simple bit of code:

$(".twitter-share-button").attr("href", "https://twitter.com/intent/tweet?text=" + quoteContent + " " + quoteSource);

This finds the element on my page with the class .twitter-share-button and changes its attributes. I specify which attribute I want to change (the “href”) followed by what I want to change it to. In this case, I want the first part of the formulaic URL Twitter has given us, followed by the text I want to appear in the tweet. We can represent that by quoteContent, a space, and quoteSource.

Testing and evaluating

After adding my JavaScript code to my CodePen and making sure it worked properly, I moved everything over to GitHub, where my website is hosted. I asked friends to test out my project on various devices, and fortunately, no one ran into problems.

Next steps

But of course, a designer’s work is never done. I’m already thinking about how I can improve on my Random Quote Generator when I have time to come back to it. Some ideas I have include:

  • Adding a way for users to suggest quotes for the database
  • A more sustainable way of storing and accessing quotes (20 quotes stored in an array like this is fine, but what about 200? 2,000? 20,000?)
  • On mobile devices, the “New Quote” button remains in focus after it is tapped — it would be nice to write code that would remove focus after a new quote is loaded
  • Right now, the “default” quote is the same every time a user visits the page, since the function is tied to the click of the button. I would like to have a different quote appear each time the page is visited.
  • Since the quotes are different lengths, the text box changes size and the “New Quote” and Tweet buttons jump around. The position of these buttons should remain consistent.

I have some ideas about how to accomplish these things, but I’m eager to move forward with my certificate so I’ll come back to this later. In the meantime, I hope you’ll visit my page and let me know of other ways I can improve on it.