Building a random quote machine with Vanilla JavaScript

This is Part 1 of an 11-part series. Each part using a different front end stack (different flavor). Starring in this flavor: Vanilla JavaScript.

If you’re curious about the next flavors, you should subscribe to Morse Wall. I think you’ll like it a lot!

Goal with this series of writings: Build a random quote machine with 19 11 different front end stacks and ship quickly.

True that…
There are always (at least) two ways to solve a problem. One is faster, the other you just don’t know yet.

You can read more about this project’s background on the project’s page.

So, what should the random quote machine do? It should spit out quotes.

These are the user stories:

As a random person on the web inspired by Greta Thunberg (or not - see note below), I want to be welcomed by a nice inspirational quote from Greta Thunberg so that I become (even more) inspired.

  1. As a random person on the web, I want to be able to click a button to get a new inspirational quote from Greta Thunberg so that I can pimp my inspiration levels.
  2. As a random person on the web, I want to be able to share on Twitter the quote the random quote machine gives me so that I can share my source of inspiration with the world.

Note: Before you get your “I have issues with Greta Thunberg” sticker-coated pitchforks out: No matter your strongly held opinions…powerful narratives you know, gotta love them. Point being: don’t @ me if you dislike Ms. Thunberg.

Random Greta Gif

Here are the different flavors available:

  1. HTML + CSS + Vanilla JS + quotes array (this flavor)
  2. HTML + CSS + Vanilla JS + JSON with quotes (members-only post)
  3. HTML + CSS + Vanilla JS + quotes REST API
  4. HTML + Vanilla JS + SAAS + quotes array (nah, because let’s be opinionated about SASS)
  5. HTML + Vanilla JS + Bootstrap + quotes array (nah, because let’s be opinionated about Bootstrap)
  6. HTML + CSS + JQuery + JSON with quotes (nah, because let’s be opinionated about JQuery)
  7. HTML + CSS + Redux + quotes array
  8. HTML + CSS + Redux + JQuery + JSON with quotes (nah, because let’s be opinionated about JQuery)
  9. HTML + CSS + Redux + Redux Thunk + JSON with quotes
  10. HTML + CSS + React + quotes array
  11. HTML + CSS + React + JSON with quotes (members-only post)
  12. HTML + CSS + React Hooks + quotes array
  13. HTML + CSS + React Hooks + JSON with quotes (members-only post)
  14. HTML + CSS + React + React Redux + quotes array (nah, because let’s be bullish about writing any new components with React Hooks)
  15. HTML + CSS + React + React Redux + Redux Thunk + JSON with quotes (nah, because let’s be bullish about writing any new components with React Hooks)
  16. HTML + CSS + React Hooks + React Redux + quotes array
  17. HTML + CSS + React Hooks + React Redux + Redux Thunk + JSON with quotes
  18. HTML + CSS + React Hooks + React Redux Hooks + quotes array (nah, because let’s be opinionated about React Redux Hooks)
  19. HTML + CSS + React Hooks + React Redux Hooks + Redux Thunk + JSON with quote (nah, because let’s be opinionated about React Redux Hooks)

If you are new here, you may wonder why I am overcomplicating a really simple application that can be shipped in 3 lines of functional Vanilla JavaScript. And the reason is: Shipping a simple app in a simple environment with fewer moving parts = great way to practice a new way to solve a problem. This is the spirit behind the Making a random quote machine in a few different flavors series. Enjoy!


In Part 2 (to be posted next week), I will cover a second flavor and will be storing the quotes in a separate JSON file.

If you’re curious about the next flavors and would like to make a writer very happy today, you should subscribe to Morse Wall.


This is a simple project. Flavor #1 has essentially 3 lines of functional JavaScript code.

The URL to the source code for each flavor is linked at the bottom of each section in this series.

Flavor #1: HTML + CSS + Vanilla JS + quotes array

HTML and CSS aside (they can be found in the Github repo for flavor #1). I’m into Vanilla JavaScript universe in flavor #1. The data (quotes) are inside an array.

I’ve scraped the quotes with the help of Spider, a point&click scraping tool built by Amie-Chen. So, with the help of Spider, you can also go ahead and easily collect quotes from any prolific public figure you choose.

When I was done scraping, I’ve then downloaded a JSON from Spider and copy-pasted the quotes into an array inside my script.js. There are only 3 quotes in the code snippet below (so I can illustrate the point), but many more quotes in the array in production.

// script.js
//defining an array for the quotes
const quotes = [
  {
    quoteText:
      '"Many of you appear concerned that we are wasting valuable lesson time, but I assure you we will go back to school the moment you start listening to science and give us a future."',
    quoteAuthor: "Greta Thunberg",
  },
  {
    quoteText:
      '"I was fortunate to be born in a time and place where everyone told us to dream big. I could become whatever I wanted to. I could live wherever I wanted to. People like me had everything we needed and more. Things our grandparents could not even dream of. We had everything we could ever wish for and yet now we may have nothing. Now we probably don’t even have a future any more."',
    quoteAuthor: "Greta Thunberg",
  },
  {
    quoteText:
      '"That future was sold so that a small number of people could make unimaginable amounts of money. It was stolen from us every time you said that the sky was the limit, and that you only live once. You lied to us. You gave us false hope. You told us that the future was something to look forward to."',
    quoteAuthor: "Greta Thunberg",
  },
];

Given I want a random quote to be ready for me when the quote machine loads, I need to call a function (that I still need to define) that fetches a random quote and renders it my HTML.

// script.js
// inject a quote on screen when app loads
injectQuote();

And given I also want a new random quote when the user clicks a button, I’ve added a click event listener to the HTML element with new-quote id.

In the HTML, setting up new-quote id (as always, you can check the full source code in the repo. Also linked at the bottom of this write-up):

<!-- index.html -->
<button id="new-quote" class="new-quote">Get New Quote</button>

Back to JavaScript, adding the click event listener:

// script.js
//inject a quote on screen when "Get New Quote" button is clicked
document.getElementById("new-quote").addEventListener("click", function () {
  injectQuote();
});

injectQuote function

The bit missing is to define the function I’ve mentioned above that will fetch a random quote from my quotes array and render it in my HTML. I’m calling that function injectQuote.

// script.js
//function to access random quote from array and inject it together with author on HTML
function injectQuote() {}

injectQuote needs to pick a random quote from quotes, so let’s do that first thing. I’ll be incrementally expanding injectQuote in each of the following code snippets, to the point it will be clear it would have been better to break injectQuote down into smaller functions (huh…)

// script.js
//function to access random quote from array and inject it together with author on HTML
function injectQuote() {
  //access random quote from quote array
  let randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
}

After fetching a random quote, injectQuote should render the quote text and and quote author in my HTML.

// script.js
//function to access random quote from array and inject it together with author on HTML
function injectQuote() {
  //access random quote from quote array
  let randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
  //inject random quote on HTML
  document.getElementById("text").innerHTML = randomQuote.quoteText;
  let quoteTextElem = randomQuote.quoteText;
  //inject author on HTML
  document.getElementById("author").innerHTML = "- " + randomQuote.quoteAuthor;
  let quoteAuthorElem = " - " + randomQuote.quoteAuthor;
}

With the above in production, the random quote machine beautifully renders a new quote upon page load and when a user clicks a button requesting a new quote.


Making the machine tweet


However, I haven’t made the Tweet Quote button work yet. So, to invoke Twitter Web Intents, injectQuote should URL-encode the tweet text, concatenate it with https://twitter.com/intent/tweet?text= and pass it to the HTML element’s href.

In the HTML, setting up tweet-quote id:

<!-- index.html -->
<button class="tweet-quote">
  <a id="tweet-quote" href="twitter.com/intent/tweet" target="_blank"
    ><em class="fab fa-twitter"></em>Tweet Quote</a
  >
</button>

And back to JavaScript:

//script.js
//function to access random quote from array and inject it together with author on HTML
function injectQuote() {
  //access random quote from quote array
  let randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
  //inject random quote on HTML
  document.getElementById("text").innerHTML = randomQuote.quoteText;
  let quoteTextElem = randomQuote.quoteText;
  //inject author on HTML
  document.getElementById("author").innerHTML = "- " + randomQuote.quoteAuthor;
  let quoteAuthorElem = " - " + randomQuote.quoteAuthor;
  //defining tweet text
  let contentQuote = quoteTextElem + quoteAuthorElem;
  //generate url available for Twitter intent and inject url on HTML
  document.getElementById("tweet-quote").href =
    "https://twitter.com/intent/tweet?text=" + contentQuote;
}

Ok, now the random quote machine ships all the required user stories.

The issue here though is that some of Greta’s quotes are longer than 280 characters (better than 140 char, I know. Thanks @jack). I have to truncate the quote text to allow the user to tweet the quote without having to delete characters. injectQuote (now already doing far too much for a single function) needs some adjustments.

// script.js
//function to access random quote from array and inject it together with author on HTML
function injectQuote() {
  //access random quote from quote array
  let randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
  //inject random quote on HTML
  document.getElementById("text").innerHTML = randomQuote.quoteText;
  let quoteTextElem = randomQuote.quoteText;
  //inject author on HTML
  document.getElementById("author").innerHTML = "- " + randomQuote.quoteAuthor;
  let quoteAuthorElem = " - " + randomQuote.quoteAuthor;
  //truncating quote text in case full tweet gets to be over 280 characters
  let contentQuote = quoteTextElem + quoteAuthorElem;
  if (contentQuote.length > 280) {
    let charCountAuthor = quoteAuthorElem.length;
    const extraStylingChar = "..." + '"';
    let extraCharCount = extraStylingChar.length;
    let subString =
      quoteTextElem.substring(0, 280 - extraCharCount - charCountAuthor) +
      extraStylingChar +
      quoteAuthorElem;
    //generate url available for Twitter intent and inject url on HTML
    document.getElementById("tweet-quote").href =
      "https://twitter.com/intent/tweet?text=" + subString;
  } else {
    //generate url available for Twitter intent and inject url on HTML
    document.getElementById("tweet-quote").href =
      "https://twitter.com/intent/tweet?text=" + contentQuote;
  }
}


Done. The random quote machine is ready to receive any random person on the web.

If you think a great Greta Thunberg quote is missing, I’ll be happy to include it. Pull requests are more than welcome in the Github repo for flavor #1.


Acknowledgement

The following goes without saying, but here it comes anyways: Please note that in this ever changing world of technology, I am writing this article in July 2019 (hello, summer!) and alternate solutions might have become available as you read this writing.


In Part 2 (to be posted next week), I will cover a second flavor and will be storing the quotes in a separate JSON file.

If you’re curious about the next flavors, you should subscribe to Morse Wall. I think you’ll like it a lot!


So, what did you like about this post?  Come say hello on Twitter!

Also, if you have built a random quote machine after reading this post, share it as comment to the tweet above on Twitter. Really excited to see what you create!

Happy coding!


Where to find me:

Follow me on Twitter:

Follow Pat Eskinasy on Twitter

You can always get my latest writings directly to your email address by subscribing to Morse Wall.


UPDATE

Part 2 of this series has now been published. Go check it out! I'm storing the quotes in a separate JSON file in the second flavor.