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.
- 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.
- 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.
Here are the different flavors available:
- HTML + CSS + Vanilla JS + quotes array (this flavor)
- HTML + CSS + Vanilla JS + JSON with quotes (members-only post)
- HTML + CSS + Vanilla JS + quotes REST API
HTML + Vanilla JS + SAAS + quotes array(nah, because let’s be opinionated about SASS)HTML + Vanilla JS + Bootstrap + quotes array(nah, because let’s be opinionated about Bootstrap)HTML + CSS + JQuery + JSON with quotes(nah, because let’s be opinionated about JQuery)- HTML + CSS + Redux + quotes array
HTML + CSS + Redux + JQuery + JSON with quotes(nah, because let’s be opinionated about JQuery)- HTML + CSS + Redux + Redux Thunk + JSON with quotes
- HTML + CSS + React + quotes array
- HTML + CSS + React + JSON with quotes (members-only post)
- HTML + CSS + React Hooks + quotes array
- HTML + CSS + React Hooks + JSON with quotes (members-only post)
HTML + CSS + React + React Redux + quotes array(nah, because let’s be bullish about writing any new components with React Hooks)HTML + CSS + React + React Redux + Redux Thunk + JSON with quotes(nah, because let’s be bullish about writing any new components with React Hooks)- HTML + CSS + React Hooks + React Redux + quotes array
- HTML + CSS + React Hooks + React Redux + Redux Thunk + JSON with quotes
HTML + CSS + React Hooks + React Redux Hooks + quotes array(nah, because let’s be opinionated about React Redux Hooks)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!
My favourite formula for solving a software development problem
— Morse Wall (@morsewall) July 15, 2021
1) Get it done fast and cheaply
2) Solve the same problem in 11 different ways because *shiny new thing* syndrome
🙃Ha!
Over the next weeks I'll write about 11 different ways to build a random quote machine pic.twitter.com/gLBWItAkCi
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:
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.