Show & hide div in JS w/ 2 clicks (how)
Tags: flatironschool, javascript, rails, toggle
Published: 2021-06-27 02:17:27

I recently completed my Javascript project at Flatiron School. It is a Single Page Application with a JS frontend and a Ruby and Rails backend. 

It's a song sharing site where you can see songs that have been shared, post your own songs to share, and see the genres the site has as categories along with their descriptions.

I wanted users to have functionality to see the genre info encompassed in a div, but only when they wanted to via click of a button, along with allowing users to hide the genre info by clicking the same button.

I spent a good amount of time trying to make a button that on first click would display the div of genre info, on the second click would hide the genre info, and so on and so forth. I also wanted the button's text to change depending on whether a click of it would be showing or hiding genre info. 

I got like the first couple of toggles of the button working successfully to where the div would display and hide, and button text changed accordingly. However, this itself took quite a lot of code and I realized that having the functionality correctly working in the event of any number of button clicks happening would be very burdensome and lengthy the way I was originally coding it.

I did research and with that figured out a better and simpler way to toggle the div's display using Javascript. Here's how: 

-First, I created one button for this in index.html like so. Just one button! Give the button an id so we can use querySelector to grab the button later: 

```<button type="button" id="see-genres-button">See all genres and their descriptions</button>```

-Then, I created a div with an id of genre-container. When this div is displayed by click a get fetch will also happen and that will show my genres in the displayed div. This was all the html for this step: 

```<div id="genre-container">```

Next, in index.js I wrote the following querySelectors to find both my genre container and my button for seeing and hiding genre info:

```let genresContainer = document.querySelector("#genre-container");
let genresButton = document.querySelector("#see-genres-button");``` 

-I then created a variable called showGenres in index.js and set it equal to false (explained a bit later): 

```let showGenres = false;```

-Next, in index.js I created a hash with two key-value pairs. The keys should be the two different strings you want your button to be able to display when toggled, and the values of these keys should be the opposite toggled version of the string of its key, like so: 

```let buttonStates = {
  "See all genres and their descriptions":
    "Hide the genres and their descriptions",
  "Hide the genres and their descriptions":
    "See all genres and their descriptions",
};```

Note on the above^: The "see genres" type strings need to be typed in the above object exactly the same as how the text is typed in the button tag on the html for this to work. Thus, the 2 strings of ```"See all genres and their descriptions"``` are typed exactly the same as the text in my button tag a few steps above. (The reasoning for all of this will become apparent in my next explanation). 

Then, I created an event listener on my genresButton like so (explanation of how this all works right below):
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a9m7perlgvsrm3994ofz.png)

So how does this listener work with the above 2 variables I set? Let me explain: 

-Line 94: We start a click event listener on our genres button.

-Line 95: We set showGenres equal to the opposite of showGenres. The showGenres variable was created and set to false from above this listener, but as shown, as soon as this click event listener happens, showGenres will be set from false to true (implying that it is true that we now want to show our genres).

-Line 96: We set up an if statement to see if showGenres is true. 

-Line 97-98: If showGenres is true, in these lines we will set the style on the genres container to display with inline-block, you can ignore the other styles.... all that is needed here to display the genres-container div is setting the display to inline-block, the rest is extra styling of my own. 

-Line 99: Based on my app, I call the getGenres function here which fetches my genres and then renders them into the genre-container div that is now displayed to the page. 

-Line 100-102: Conditional logic in an else statement so that if the showGenres variable is false, I change the display of the genre-container to "none" which hides the container. Say for example, we just hopped on my site and for the first time clicked the button to show the genre info. Show genres would have been set to true then from `showGenres = !showGenres;`. Then the genre info displays on page. The next time we click the button for displaying/hiding, `showGenres = !showGenres;` will now take the showGenres variable which is now currently true and set showGenres to the opposite, thus making showGenres now equal to false. Because showGenres is now false, our else logic will run and hide the display of the genres-container. That is how this logic regarding the showGenres variable works to show the genres and hide the genres accordingly.

-Finally, Line 104:

This line is responsible for why the button text changes from the show message to the hide message. In line 104 we are using the buttonStates variable we defined above... here is the buttonStates variable again: 

```let buttonStates = {
  "See all genres and their descriptions":
    "Hide the genres and their descriptions",
  "Hide the genres and their descriptions":
    "See all genres and their descriptions",
};```

In line 104 of the above listener, we are taking the innerText of our genresButton (which starts off as `"See all genres and their descriptions"` from how our original html button is), and we are setting this innerText equal to the value of the key of that innerText string in the buttonStates object by doing `buttonStates[genresButton.innerText]`. So on the first click of the button when it originally said "See all genres and their descriptions", after the click the button will now show the value of that string's key in the buttonStates object, so the button will then display "Hide the genres and their descriptions". On the next click of the button that now says "Hide the genres and their descriptions", the button after clicked will now then show the value of that string's key in the buttonStates object, so the button will then display "See all genres and their descriptions". Now the button text will correctly change from the show message to the hide message every time it is clicked. 

These steps are how I got my div displaying and hiding with the clicks of one button while that button's text correctly changed as well! Hopefully this is helpful to someone!