This blog post is part of the series “Learning web development” – which teaches people who have never programmed how to create web apps with JavaScript.
To download the projects, go to the GitHub repository learning-web-dev-code
and follow the instructions there.
I’m interested in feedback! If there is something you don’t understand, please write a comment at the end of this page.
In this chapter, we learn how to create plain objects with properties. We use them to create a simple flash card app.
The following statement creates a plain object and assigns it to the variable purchase
:
const purchase = {
product: 'toothbrush',
quantity: 1,
};
The comma at the end (a trailing comma) is optional.
In a way, a plain object is a group of variables – it groups together related pieces of data that we can access via names. In contrast, in an array, we access related pieces of data via numberic indices.
This is what we can do with purchase
:
We can read a property such as .quantity
(we get that property):
> purchase.quantity
4
And we can write to a property (we set that property):
> purchase.quantity += 1;
> purchase
{ product: 'carrot', quantity: 5 }
toggle-content.html
The project toggle-content.html
is a preparation for the next project: We learn how to show and hide content. This project can be used via a file:
URL.
This is the HTML:
<p>
<a href="">Toggle the content</a>
</p>
<p id="content" class="hidden">
[...]
</p>
The following CSS hides the HTML element #content
if it has the class hidden
:
#content.hidden {
display: none;
}
Therefore, initially, the content inside <p>
is hidden. The link toggles the display:
This is the JavaScript code that does the toggling:
const content = document.querySelector('#content');
document.querySelector('a')
.addEventListener(
'click',
(event) => {
event.preventDefault();
content.classList.toggle('hidden'); // (A)
}
);
What is going on in line A? .classList
gives us a “list” (a data structure loosely similar to an array) with the classes of content
. Method .toggle()
of the list adds or removes class hidden
as necessary. Line A is equivalent to the following code (which demonstrates more methods of class lists):
if (content.classList.contains('hidden')) {
content.classList.remove('hidden');
} else {
content.classList.add('hidden');
}
If we remove or add class hidden
, CSS immediately reacts to the change and shows or hides #content
.
flash-cards/
Project flash-cards
shows us flash cards, randomly:
This project uses JavaScript modules – which is why we need to run a web server:
cd learning-web-dev-code/projects/
npx http-server
After that, the project is available at:
http://127.0.0.1:8080/flash-cards/flash-cards.html
From now on, I will not explain how to use http-server
anymore. When it doubt, use it to run a web app.
data.js
: the flash card data The flash cards are defined in their own module, data.js
:
export const data = [
{ front: 'perro', back: 'dog' },
// ...
];
flash-cards.html
: HTML This is the user interface, defined in HTML:
<p>
<button id="nextCard">Next Flashcard</button>
</p>
<p>
<a href="" id="toggleBack">Toggle Back</a>
</p>
<div id="flashCard">
<p id="front"></p>
<hr>
<p id="back"></p>
</div>
<p>
<span id="cardNumber"></span> of <span id="cardTotal"></span>
</p>
The last <p>
displays texts such as “2 of 10” – “cards” is implied.
flash-cards.html
: CSS We need CSS so that we can easily reveal and conceal the back of a flash card:
#back {
display: none;
}
#back.revealed {
display: initial;
}
By default, the back is hidden. If we add the class .revealed
, we can see it.
The following CSS centers the user interface horizontally and gives it a maximum width of 40 rem (a CSS unit that is useful for specifying lengths in CSS):
html {
/* top right bottom left */
margin: 2rem auto 2rem auto;
max-width: 40rem;
}
We surround the flash card with border that has rounded corners (thanks to border-radius
):
#flashCard {
border: solid thin gray;
border-radius: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
padding-bottom: 1rem;
}
flash-cards.html
: JavaScript We start by importing the tools and data we need:
import { shuffleArray } from './utils.js';
import { data } from './data.js';
shuffleArray()
is a function that, unsurprisingly, shuffles the elements of an array. We’ll take a look at its code later. Shuffling guarantees that each time we go through the cards, we (generally) see them in a different order. An alternative would have been to simply pick a random card each time but then we are much more likely to see the same card twice in a row.
Variable currentIndex
records where we currently are inside the array data
:
let currentIndex = 0;
Function showCard()
displays an element of array data
in the user interface:
const showCard = (index) => {
const front = document.querySelector('#front');
const back = document.querySelector('#back');
const cardNumber = document.querySelector('#cardNumber');
// Make sure the back is hidden
back.classList.remove('revealed');
const card = data[index];
front.innerText = card.front;
back.innerText = card.back;
cardNumber.innerText = index + 1;
};
The following function starts a new round, “restarting” the game if you will. It is the first function we call when the web app starts because it sets up everything correctly.
const startNewRound = () => {
const cardTotal = document.querySelector('#cardTotal');
shuffleArray(data);
cardTotal.innerText = data.length;
currentIndex = 0;
showCard(currentIndex);
};
This function goes to the next card:
const goToNextCard = () => {
currentIndex = currentIndex + 1;
if (currentIndex >= data.length) {
startNewRound(); // sets currentIndex to 0
} else {
showCard(currentIndex);
}
}
It first increments currentIndex
:
data
then we are past the last card (whose index is data.length - 1
) and have to start a new round.The following function toggles whether the back is revealed or not:
const toggleBack = () => {
const back = document.querySelector('#back');
back.classList.toggle('revealed');
};
utils.js
The following utility function uses the Fisher–Yates algorithm to shuffle an array:
export const shuffleArray = (arr) => {
for (let current = arr.length - 1; current >= 1; current--) {
const randomPick = getRandomInteger(current);
// Swap elements at the indices `current` and `randomPick`
const tmp = arr[current];
arr[current] = arr[randomPick];
arr[randomPick] = tmp;
}
return arr;
};
That algorithm is actually remarkably simple:
tmp
to do that.If we did the same with playing cards, it would look like this:
In project flash-cards
, there was in interesting phenomenon:
data
. And we had an index for the current flash card.The former is sometimes called a model. The latter is sometimes called a view for the model. Handling events and updating model and view is sometimes called a controller, but that term is not as common as the other two.
The following two functions “transport” the model to the view – they update the view so that it reflects the model:
showCard()
startNewRound()