Completing 30 vanilla JS projects in 30 days — Part 2

Ruth Newman
9 min readMay 16, 2019

--

Last month I challenged myself to practise my JavaScript fundamentals, by building a web application with vanilla JavaScript every day for the entire month of April — 30 projects over 30 days.

Somehow, I did it and you can find the full list of all my projects at the Github repository here (they are all hosted on Github pages and the full list includes the links to each hosted site as well as the individual project’s Github repo).

I chronicled the first week of projects in a previous post (you can read that here). It was a great start — delving into different skills I wanted to explore, finding inspiration and adding a personal spin to common project ideas. I took this further in the second week of projects, focusing on projects that responded to user input in different ways, or exploring a couple more public APIs.

Day 8: “My Calculator App” — https://ruthenewman.github.io/MyCalculatorApp/

Day 8 was a tricky one, and overall turned out to be one of my least preferred projects of the entire month. I had a lot of issues that needed debugging, but I persisted and managed to build an interactive web application that conducted basic calculations (addition, subtraction, multiplication and division), and rendered the results in a calculator-like interface. The design could have been improved, but ultimately I added a media query so the calculator and its features were resized appropriately on mobile devices.

The calculator interface design

Adding multiple event listeners by iterating over numerous elements of the same class (e.g. numbers or operators) was a useful practical example of the DRY principle in practice, and it was useful to consider type conversion between integers and strings when taking user input, conducting calculations and rendering the results.

Day 9: “From Manchester to the World” https://ruthenewman.github.io/FromManchesterToTheWorld/

I have noticed that a lot of developers’ portfolios make use of the Google Maps API for web or mobile application ideas, and as such I figured it was something worth getting familiar with to some degree or another. I knew with one day only, I couldn’t make the most complicated application, but I decided to render a custom map onto the screen, and include bespoke icons for specific locations. These icons would, in response to a user click, detail the name of the location in question.

My hometown, as referenced in the previous post, is Manchester, and so I chose some favourite haunts in the city as my locations, and added a Manchester-specific icon (the humble worker bee), as well as thematic icons such as a football or greek drama masks to represent three of the top theatres in the city. It’s a project I definitely am considering returning to, to expand upon beyond a one-day project with a limited number of locations, as mapping applications are in vogue due to the almost limitless potential of what you can represent.

With three of the locations selected

I called on an addMarker function to create each pointer and provide the image, longitude and latitude and text details (e.g.):

addMarker({    
coords:{
lat: 53.474331436,
lng: -2.240332372},
iconImage: "./beeicon.png",
content: "<h3>Albert Square</h3>"
});

Day 10: “Super Star Ratings” — https://github.com/RuthENewman/SuperStarRatings

The next project responded to user input — a single page film ratings app, using a range of acclaimed (and perhaps some less acclaimed Hindi-language films of the last few years).

As this was a front-end project only, all the scores reset on refresh. This became, as such, another project I could return to in future, beyond a single day effort, and add a backend which saves changes to the ratings after the user returns to the site. Without a separate API, the index.js file started with an object with all the film titles as keys and the initial ratings as values.

const ratings = {  
raazi: 4.7,
badhaaiHo: 3.4,
stree: 4.0,
hindiMedium: 3.5,
dangal: 4.4,
toiletEkPremKatha: 3.5,
bareillyKiBarfi: 3.2,
badrinathKiDulhania: 3.3,
pink: 4.1, sultan: 3.0,
neerja: 4.7,
kapoorAndSons: 4.0,
udtaPunjab: 4.4,
bajiraoMastani: 4.5,
badlapur: 2.4,
bajrangiBhaijaan: 4.0,
piku: 4.7,
queen: 4.7,
tanuWedsManuReturns: 3.0,
bhaagMilkhaBhaag: 4.0,
.... }

Pulling the ratings out of the front end repository into a separate API would also be something to consider in expanding this project further. It ends up looking something like this:

On the frontend side of things, it could be upgraded by adding images for each of the films (or even trailer videos from Youtube, or links to Netflix, Amazon Prime, Hotstar or wherever they can be watched!). All that sounds like a much meatier project which I would love to get stuck into, but for now I still had 20 days more to go of my vanilla JS challenge, so these ideas have had to be parked for a later date.

Day 11: “Net Multi Flix” https://ruthenewman.github.io/NetMultiFlix/

Whilst week two started out with what became one of my least favourite projects (see Day 8), it also included one of my favourites. Perhaps it was a favourite because it paid homage in design and name to one of the best designed websites out there today (Netflix of course, no small part of its success). Perhaps it was because it was a chance to include some extraordinary animation that is little known about in the UK or outside of the former Soviet Union at all. Perhaps it was because it was finally a multi-page application or included video?

Most likely it was a combination of the above. It allowed for a lot of time amending the CSS (which, if I had more than a single day, of course could be improved further), but served as great practise for taking a pre-thought out design and putting it on the screen. The JavaScript allowed for the user to play with the video controls, including watching in full screen.

The name comes from paying homage to the streaming giant and the Russian word for cartoons (Multifilmy)

I added several cartoons to the site, each with its own separate page (this could be refactored easily as a component with a library or framework such as React/Vue/Angular). They are all in the public domain — and as my site is limited in its content for now, multiple episodes and many more similar cartoons can be found with and without English subtitles with a quick Youtube search.

Some of the code is as readable as the below:

const video = document.querySelector('.viewer');function playAndPause() {  
if (video.paused) {
video.play();
} else {
video.pause();
}
}
video.addEventListener('click', playAndPause)

That’s the three steps of 1) navigating the DOM, and declaring a variable for your selected element; 2) creating a function which calls play or paused based on a conditional; 3) adding an event listener to the video element with a callback to the playAndPause function in response to a user click.

The rest of the code was for additional elements, event listeners and more complex functions, but it all built upon this straightforward structure.

Day 12: “WTA Whizz Tennis Quiz”https://ruthenewman.github.io/WTAWhizzTennisQuiz/

The next day’s project was a single page application that could have been built using an API of quiz questions and answers, and a front end of React components, but given this was a vanilla JS project, I needed to be able to change the question and answer options as a user clicked through the quiz.

The UI design and Question 1

Due to the lack of an API, the index.js file starts by declaring a nested array of questions, the four options and the answer (e.g. as below, with the answer missing!)

const questions =  
[["Which of these players is not among the 13 women who have finished the season as the Year Ending #1 player?",
"Victoria Azarenka",
"Kim Clijsters",
"Angelique Kerber",
"Lindsay Davenport",
"answer letter here"
],
[...all the following questions]
]

To show the question I had to set the position:

position = 0;

Then the question and answers to render based on this number and set the innerHTML:

question = questions[position][0];  
choiceA = questions[position][1];
choiceB = questions[position][2];
choiceC = questions[position][3];
choiceD = questions[position][4];
quiz.innerHTML = '<div id="question"><p id="questionText">'+question+'</p></div>';
quiz.innerHTML += '<input class="choice" type="radio" name="choices" value="A"> '+choiceA+'<br>';
quiz.innerHTML += '<input class="choice" type="radio" name="choices" value="B"> '+choiceB+'<br>';
quiz.innerHTML += '<input class="choice" type="radio" name="choices" value="C"> '+choiceC+'<br>';
quiz.innerHTML += '<input class="choice" type="radio" name="choices" value="D"> '+choiceD+'<br><br>';

And last but not least of course, increment the position variable:

position++;

The score was collected by checking if the input matched the last string in same index of the nested array, and using a conditional statement, either incrementing a ‘correct’ variable or not. The user then receives their total score after completing the quiz.

It’s a pretty tough quiz, so its hard to get this exact message at the end!

Day 13: “Avocado, Craft Beer, Latte”https://ruthenewman.github.io/AvocadoCraftBeerLatte/

Another eventual favourite started out as an attempt to give the traditional snake game a hipster twist, but I stumbled within a day to get that to work on Day 13 and parked the explorations with HTML5 Canvas for a later stage of my 30 day challenge.

I still liked my idea of give a classic game a contemporary revamp with a tongue-in-cheek reference to three of the most important aspects of the hipster lifestyle — avocados, craft beer and lattes (although I have been since informed this should be a Flat White, my personal preference for a Latte has some influence here!).

I adopted then a rock paper scissors -type of game instead, with conditional logic necessary and a “virtual hipster” for the user to compete against.

function getComputerChoice() {  
const choices = ["avocado", "beer", "latte"];
const randomNumber = (Math.floor(Math.random() * 3));
return choices[randomNumber];
}

Design-wise, I chose an Instagram-inspired gradient for the background and found free icons from shareicon.net for a user to select their option.

The instructions are on the top of the page, but my not entirely perfect game logic was based on the time of day you might consume each one (i.e. an a latte for breakfast which is defeated by an avocado for brunch/lunch, which is then defeated therefore by the craft beer in the evening. The coffee wakes you up in the morning again so the latte defeats the craft beer.

For this project the game function was called in response to a user click, with the argument passed depending on which icon was selected:

avocadoDiv.addEventListener('click', function() {       game("avocado");  })   
beerDiv.addEventListener('click', function() { game("beer"); }) latteDiv.addEventListener('click', function() { game("latte"); })

The game function uses a switch statement to call other functions based on the game logic, the user’s choice and the random ‘computer choice’:

function game(userChoice) {  
const computerChoice = getComputerChoice();
switch (userChoice + computerChoice) {
case "latteavocado":
case "beerlatte":
case "avocadobeer":
userLoses(userChoice, computerChoice);
break;
case "avocadolatte":
case "lattebeer":
case "beeravocado":
userWins(userChoice, computerChoice);
break;
case "avocadoavocado":
case "lattelatte":
case "beerbeer":
itsADraw(userChoice, computerChoice);
break;
}
}

All in all, a much more achievable project that turned out quite nicely, after some time spent struggling with snake (which may have been attempted again later in the month, with greater success).

Day 14: “Random Poem Generator”https://ruthenewman.github.io/RandomPoemGenerator/

One of the most frequent projects developers tend to make with vanilla JavaScript especially, is a Random Quote Generator. I couldn’t think of many ways of making that more original or exciting, so after exploring free public APIs I discovered the Poemist API and figured random poems would at least be slightly more original.

The Poemist API currently only allows for a get request for a random poem, and includes poems in a range of languages, and with all kinds of formatting. To make more of the poems more readable, I formatted the text using a regular expression to put anything after a full stop onto a new line.

function getPoem() {         
fetch(no_cors+'https://www.poemist.com/api/v1/randompoems')
.then(response => response.json())
.then(data => {
let fivePoems = data;
let currentPoem = fivePoems[0];
poemDiv.style.display = 'block';
titleText.textContent = currentPoem.title;
authorText.textContent = currentPoem.poet.name;
thisPoemContent = currentPoem.content;
formattedContent = thisPoemContent.replace( /\.(\s+)/g, '<br /><br />');
contentText.innerHTML = formattedContent;
})

With a day for this project, any greater reformatting would have to be saved for another time, with the option of even building one’s own, well-maintained API to make requests to instead.

But for now, for a chance to generate a site that was marginally more original within a day using only vanilla JS, it worked perfectly fine to complete my second week of the challenge.

The site fetches a random poem from the Poemist API by clicking on the button above

--

--