Multi-faced Flip Card with a Click (Part 3: JavaScript)
Tags: tutorial, html, css, javascript
Published: 2020-07-02 10:56:01

_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](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-part-i-o6c)
* Part II: [CSS](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-part-2-css-3oam)
* Part III: [JavaScript](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-part-3-javascript-2f7f)
* Bonus: [Going further into 3D space](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-bonus-going-further-into-3d-space-2jff)

___

# 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](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics).

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](https://www.w3schools.com/howto/howto_js_toggle_class.asp) 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](https://developer.mozilla.org/en-US/docs/Web/API/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()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) with a `(‘.class__name’)` selector, the first element in the document with the `class` of “class__name” is returned. To return all matches to that `class`, use `querySelectorAll()`. The next step should be to save this result inside a variable. When using a selector of `(‘#id__name’)`, the element with the unique `id` called “id__name” will be returned and should be saved in its own variable as well. 

```javascript
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()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/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. 

```javascript
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](https://www.w3schools.com/jsref/met_win_settimeout.asp) 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. 

```javascript
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()](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/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.

```javascript
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. 

{% codepen https://codepen.io/santiagocodes/pen/zYrwWed %}

## 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. 

{% codepen https://codepen.io/santiagocodes/pen/bGErdjY %}

If you liked what you read hit that :heart: 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. 

:computer: **article.close()**

## Resources 

* [JavaScript Basics](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics)
* [Toggle a Class](https://www.w3schools.com/howto/howto_js_toggle_class.asp)
* [element.classList](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList)
* [document.querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) 
* [form.reset()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset) 
* [setTimeout](https://www.w3schools.com/jsref/met_win_settimeout.asp)
* [addEventListener()](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)