JavaScript JavaScript and the DOM Making Changes to the DOM Styling Elements

Seth Stephenson
Seth Stephenson
7,632 Points

Weird question about some extra code I added (conditional ternary operator) and an unexpected behavior

I added this ternary to the function that will, addition to the div id "toggleList" display being set to none, change the button text to "Reveal List". When clicked again the "toggleList" display will be set to "block" and the button text will be set to "Hide List". The functionality works as expected, but only after you click the button once and it does nothing. In pursuit of clarity, you click the button once, nothing happens. Click the button again and the "toggleList" div display is set to none and the button text is set to "Reveal List". Click the button again and everything resets to its previous state. The button will continue to work as expected until the page is refreshed.

I added an inline style to the index.html file:

<button id="toggleList" style="display:block">Hide List</button>

I then removed the inline style and added an additional condition to my ternary and this fixed the extra click behavior. I've included both versions of the app.js file bellow. Can anyone clue me in to what's causing this behavior? I am boggled, but would really like to figure this out. Thanks for any help!

app.js file with the extra click:

const toggleList = document.getElementById('toggleList');
const listDiv = document.querySelector('.list');
const input = document.querySelector('input');
const p = document.querySelector('p.description');
const button = document.querySelector('button.description');

toggleList.addEventListener('click', () => {
  (listDiv.style.display == 'block') 
  ? 
  (listDiv.style.display = 'none') 
  && 
  (document.getElementById('toggleList').textContent = 'Reveal List') 
  : 
  (listDiv.style.display = 'block') 
  && 
  (document.getElementById('toggleList').textContent = 'Hide List');
});

button.addEventListener('click', () => {
                        p.innerHTML = input.value + ':';
});

app.js file with expected behavior:

const toggleList = document.getElementById('toggleList');
const listDiv = document.querySelector('.list');
const input = document.querySelector('input');
const p = document.querySelector('p.description');
const button = document.querySelector('button.description');

toggleList.addEventListener('click', () => {
  (listDiv.style.display == '') || (listDiv.style.display == 'block')
  ? 
  (listDiv.style.display = 'none') 
  && 
  (document.getElementById('toggleList').textContent = 'Reveal List') 
  : 
  (listDiv.style.display = 'block') 
  && 
  (document.getElementById('toggleList').textContent = 'Hide List');
});

button.addEventListener('click', () => {
                        p.innerHTML = input.value + ':';
});

And, here is the entire index.html file w/o the inline style (this is used to achieve the expected behavior):

<!DOCTYPE html>
<html>
  <head>
    <title>JavaScript and the DOM</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <h1 id="myHeading">JavaScript and the DOM</h1>
    <p>Making a web page interactive</p>    
    <button id="toggleList">Hide List</button>
    <div class="list">
      <p class="description">Things that are purple:</p>

      <input type="text" class="description">
      <button class="description">Change List Description</button>

      <ul>
        <li>grapes</li>
        <li>amethyst</li>
        <li>lavender</li>
        <li>plums</li>
      </ul>
    </div>
    <script src="app.js"></script>
  </body>
</html>

And, just in case, here is the style.css file:

@import 'https://fonts.googleapis.com/css?family=Lato:400,700';

body {
  color: #484848;
  font-family: 'Lato', sans-serif;
  padding: .45em 2.65em 3em;
  line-height: 1.5;
}
h1 {
  margin-bottom: 0;
}
h1 + p {
  font-size: 1.08em;
  color: #637a91;
  margin-top: .5em;
  margin-bottom: 2.65em;
  padding-bottom: 1.325em;
  border-bottom: 1px dotted;
}
ul {
  padding-left: 0;
  list-style: none;
}
li {
  padding: .45em .5em;
  margin-bottom: .35em;
  display: flex;
  align-items: center;
}
input,
button {
  font-size: .85em;
  padding: .65em 1em;
  border-radius: .3em;
  outline: 0;
}
input {
  border: 1px solid #dcdcdc;
  margin-right: 1em;
}
div {
  margin-top: 2.8em;
  padding: 1.5em 0 .5em;
  border-top: 1px dotted #637a91;
}
p.description,
p:nth-of-type(2) {
  font-weight: bold;
}
/* Buttons */
button {
  color: white;
  background: #508abc;
  border: solid 1px;
  border-color: rgba(0, 0, 0, .1);
  cursor: pointer;
}
button + button {
  margin-left: .5em;
}
p + button {
  background: #52bab3;
}
.list button + button {
  background: #768da3;
}
.list li button + button {
  background: #508abc;
}
li button:first-child {
  margin-left: auto;
  background: #52bab3;
}
.list li button:last-child {
  background: #768da3;
}
li button {
  font-size: .75em;
  padding: .5em .65em;
}

Thanks again!

Dave StSomeWhere
Dave StSomeWhere
19,777 Points

Hi Seth,

Please check the Markdown Cheatsheet below for posting your code :arrow_heading_down:.

Also, if you post your html and css it will be easier to evaluate your code.

Thanks, :tropical_drink: :palm_tree:

1 Answer

Steven Parker
Steven Parker
171,136 Points

While block mode is the default for the element, the "display" style is not initially set to "block". The original setting is just empty.

So your first click might not make any visible change, but it sets the display mode explicitly to "block". Then the subsequent clicks toggle the mode as expected.

Adding the extra test for an empty string or presetting the value to "block" is what fixed the issue. You could also fix the issue by toggling between "" and "none" instead of "block" and "none".