Multi-faced Flip Card with a Click (Part 3: JavaScript)
Maria del Carmen Santiago
Posted on July 2, 2020
More than just your average Flip Card tutorial. Don’t just flip your card on hover, use JavaScript to flip it on command. Includes instructions on how to change the reverse face to show a different face each time and tricks to give the card a nice 3D effect while flipping.
This series will be divided into three parts (plus a fun bonus at the end):
- Part I: HTML
- Part II: CSS
- Part III: JavaScript
- Bonus: Going further into 3D space
Part III: JavaScript
Let’s start with my favorite part of this project… the JavaScript! We’ll start with the function that flips the card. Then I will discuss the function that validates the input and gives us the appropriate response card on the back. Next, we will move on to the function that takes care of flipping the card back around to the front face again. Finally, I discuss the event listeners we will have to add in order for these functions to execute when needed.
In case you feel you need to review your JS basics, click here.
At the bottom of the page, you will find two codepens. The first is a codepen for this project and the second is for a similar, but more basic, project.
Let’s get started!
flipCard Function
The function to flip the card is a very short one. If you recall from the previous article in this series, we have a CSS ruleset of .card__content.is-flipped {transform: translateX(-100%) rotateY(-180deg);}
. So what we will be doing here is selecting the card__content
element in our javascript and toggling the “is-flipped” class
to make that <div>
flip. Remember that the container stays put while the content flips.
When you toggle a class
you can think of it like an on/off switch that will add or remove the class
according to its previous state. You access an element’s list of classes using element.classList. From there you can do things like .toggle(‘class__name’)
, adding a class to the element using .add(‘class__name’)
, among other things.
Quick JS Review: When using document.querySelector() with a
(‘.class__name’)
selector, the first element in the document with theclass
of “class_name” is returned. To return all matches to thatclass
, usequerySelectorAll()
. The next step should be to save this result inside a variable. When using a selector of `(‘#idname’), the element with the unique
id` called “id_name” will be returned and should be saved in its own variable as well.
const cardContent = document.querySelector('.card__content');
function flipCard() {
cardContent.classList.toggle('is-flipped');
}
checkNumber Function
We have a card with a <form>
on the front that will validate a number given by the user. The card will flip using the previous function and on the back of it, we will get… nothing. Do you remember the .card__back
CSS ruleset? If you take a look at it, it has a display: none;
declaration that will make all the elements with this class
“disappear” from our view.
So, let’s back up a little and go step by step on this one. First, we will create three variables in which we will store the three different backs of the card using their unique id
s. Then we will create a function, which I have named checkNumber()
and we will pass the event on it. We pass on the event because we need to prevent the page from submitting the form and refreshing the page by using the event.preventDefault()
method.
In a variable, we will store the value given to us by the user using document.querySelector('#input__form').value
. We will then proceed to check the number using an if
statement. If the input number is equal to 6.62607015 ( one of the Planck’s constant values mentioned in Part I of this series), then we will add the class
of “display” to #card__back__one
. If you look back you will remember that in the CSS we have a ruleset of .card__back.display { display: block;}
. That is the class we will be adding, and is why #card__back__one
will show and not the others.
Now, if the input number is equal to 6.62607004 then it will be #card__back__two
that is shown and not #card__back__one
. If the user inputs any other number, #card__back__three
will be the one shown to the user instead of the other two. After adding the “display” class
to the correct card we will call the flipCard()
function we worked on before. An extra method you may want to use is the form.reset() method in order to restore the default values of our <form>
. In our case, that would set the input value back to a blank.
const card1 = document.querySelector('#card__back__one');
const card2 = document.querySelector('#card__back__two');
const card3 = document.querySelector('#card__back__three');
const input = document.querySelector('#input__form');
const form = document.querySelector('form');
function checkNumber(event){
event.preventDefault();
let inputNumber = input.value;
if (inputNumber == 6.62607015) {
card1.classList.add('display');
} else if (inputNumber == 6.62607004) {
card2.classList.add('display');
} else {
card3.classList.add('display');
}
flipCard();
form.reset();
}
flipCardBack Function
Do we need another function to flip the card back to the front of the card? In this case we do as we need to remove that “display” class
we just added. We do not want the back of the card to disappear before it has flipped completely and the page is already showing us the front. That is why we will use the setTimeout method for this one. Inside setTimeout
we will have a function that will remove the class
“display” from all of the backs of the card. This function will be executed after 2000 milliseconds (it works the same if you choose just 1000 milliseconds). This value I chose has to do with the transition time I set in the CSS (which was two seconds). We mustn’t forget to flip that card either so just reuse the flipCard
function in there.
const card1 = document.querySelector('#card__back__one');
const card2 = document.querySelector('#card__back__two');
const card3 = document.querySelector('#card__back__three');
function flipCardBack() {
setTimeout(function() {
card1.classList.remove('display');
card2.classList.remove('display');
card3.classList.remove('display');
}, 2000 );
flipCard();
}
Event Listeners
We have all of our functions, but when do they get executed? The addEventListener() method will call a function when an event happens to the target element.
The first event listener is an easy one. When a form is submitted, the checkNumber
function will be executed. The event we passed inside the parentheses is that submit.
The second event listener caused me a bit of trouble. What I forgot was that, even though all the buttons at the back have the same class and look the same, they are three different buttons. So initially I added an event listener like the following btnBack.addEventListener(click, flipCardBack);
and it worked… the first time around. After the first full flip, I would enter another number on the <form>
, and when it flipped a second time I was getting the card face I wanted, but the button wouldn’t flip back to the front.
It was driving me a bit crazy that the button would work once, but not the second time around. Well, it turned out that I needed to add an event listener for each button separately. You could place an id
on each button and have an event listener added to each like so, const btnBack1 = document.querySelector('#btn__back1').addEventListener(‘click’, flipCardBack)
. That is fine when you only have three buttons, but what if there were more? That is where forEach
comes in handy.
const form = document.querySelector('form');
const btnBack = document.querySelectorAll('.btn__back');
form.addEventListener('submit', checkNumber);
btnBack.forEach(function(btn) {
btn.addEventListener(‘click’, flipCardBack);
});
The Code
Here is the CodePen of the complete project. Feel free to fork it and play around with it. I just ask that you share your code if you make something cool with it! I would enjoy having a look and learning something new.
Alternative Simpler Solution
There is a simpler way of doing all of this. You could just make one back of the card instead of three and change the image using image.src
as shown below, but that will limit you in terms of having completely different card faces with different layouts.
If you liked what you read hit that ❤️ on the left or wherever it is. If you really liked it don’t forget to share it with the community by hitting that dot-dot-dot icon near the heart.
💻 article.close()
Resources
Posted on July 2, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.