bodemiller1
bodemiller1

Reputation: 83

onclick requires two clicks the first time

I've just begun to learn JavaScript.

I wrote a simple dropdown menu, but when you initially load the page, two clicks on the "dropdown"- button (with onclick attribute) are required for the link list to be displayed.

After that, it works as intended - you only need to click one time on the button to display/hide the list.

But why do I have to click two times on the button after intially loading the site?

Here's my HTML/CSS:

#dropbtn {
    background-color: #4CAF50;
    color: white;
    padding: 16px;
    font-size: 16px;
    border: none;
    cursor: pointer;
}

#dropdown {
    position: relative ;
    display: inline-block;
}

#dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

#dropdown-content a {
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
}

#dropdown-content a:hover {background-color: #f1f1f1}

/*#dropdown:hover #dropdown-content {
    display: block;
}*/

#dropdown:hover #dropbtn {
    background-color: #3e8e41;
}
<h2>Dropdown Menu</h2>
<p>Just a simple menu with link list</p>

<div id="dropdown">
  <button id="dropbtn" onclick="myFunction()">Dropdown</button>
  <div id="dropdown-content">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>
<script>

function myFunction() {
if (document.getElementById('dropdown-content').style.display == "none") 
         {document.getElementById('dropdown-content').style.display = "block";}
else {document.getElementById('dropdown-content').style.display = "none";}
    
    
}

</script>

Upvotes: 2

Views: 2748

Answers (7)

Vasilis Zisis
Vasilis Zisis

Reputation: 33

Another way you can do it, which involves Dennis Spierenburg answer is to change

    function myFunction() {
    if (document.getElementById('dropdown-content').style.display == "none") 
     {document.getElementById('dropdown-content').style.display = "block";}
    else {document.getElementById('dropdown-content').style.display = "none";}
    }

to

    function myFunction() {
      const myElement = document.getElementById('dropdown-content');
      const myElementDisplay = getComputedStyle(myElement);
      if (myElementDisplay.display === "none") {
        myElement.style.display = "block";
    }
      else {
        myElement.style.display = "none";
      }
    }

Upvotes: 0

Luis E. Azmouz
Luis E. Azmouz

Reputation: 9

I was having the same issue, basically the first click activates the event handler in Javascript and the second click is the one that actually works.

To work your way around this call the event handler as soon as the page loads in your HTML file:

<body onload="myFunction()">

This will also make the first click work when using a phone.

Upvotes: 0

Dennis Spierenburg
Dennis Spierenburg

Reputation: 643

@sdleihssirhc tells in another post how to check if a element is being displayed or not. check out this post.

return element.currentStyle ? element.currentStyle.display :
                          getComputedStyle(element, null).display;

This will give you the value of a styled element.

Upvotes: 0

Pranav C Balan
Pranav C Balan

Reputation: 115212

In the initial case value of display property would be undefined unless you are setting css property using inline style attribute, so toggle the if condition and code blocks.

function myFunction() {
  // cache the element for later use, which is one of the best practice 
  var ele = document.getElementById('dropdown-content');

  if (ele.style.display == "block") {
    ele.style.display = "none";
  } else {
    ele.style.display = "block";
  }
}

#dropbtn {
  background-color: #4CAF50;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

#dropdown {
  position: relative;
  display: inline-block;
}

#dropdown-content {
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  min-width: 160px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}

#dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

#dropdown-content a:hover {
  background-color: #f1f1f1
}


/*#dropdown:hover #dropdown-content {
    display: block;
}*/

#dropdown:hover #dropbtn {
  background-color: #3e8e41;
}
<h2>Dropdown Menu</h2>
<p>Just a simple menu with link list</p>

<div id="dropdown">
  <button id="dropbtn" onclick="myFunction()">Dropdown</button>
  <div id="dropdown-content">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>
<script>
  function myFunction() {
    // cache the element for later use 
    var ele = document.getElementById('dropdown-content');
    if (ele.style.display == "block") {
      ele.style.display = "none";
    } else {
      ele.style.display = "block";
    }
  }
</script>


Or set display property using inline style attribute.

<div id="dropdown-content" style="display:none">
 <a href="#">Link 1</a>
 <a href="#">Link 2</a>
 <a href="#">Link 3</a>
</div>

#dropbtn {
  background-color: #4CAF50;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

#dropdown {
  position: relative;
  display: inline-block;
}

#dropdown-content {
  position: absolute;
  background-color: #f9f9f9;
  min-width: 160px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}

#dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

#dropdown-content a:hover {
  background-color: #f1f1f1
}


/*#dropdown:hover #dropdown-content {
    display: block;
}*/

#dropdown:hover #dropbtn {
  background-color: #3e8e41;
}
<h2>Dropdown Menu</h2>
<p>Just a simple menu with link list</p>

<div id="dropdown">
  <button id="dropbtn" onclick="myFunction()">Dropdown</button>
    <div id="dropdown-content" style="display:none">
     <a href="#">Link 1</a>
     <a href="#">Link 2</a>
     <a href="#">Link 3</a>
    </div>
</div>
<script>
  function myFunction() {
    // cache the element for later use 
    var ele = document.getElementById('dropdown-content');
    if (ele.style.display == "none") {
      ele.style.display = "block";
    } else {
      ele.style.display = "none";
    }
  }
</script>


Taken from MDN Docs :

The HTMLElement.style property is used to get as well as set the inline style of an element. While getting, it returns a CSSStyleDeclaration object that contains a list of all styles properties for that element with values assigned for the attributes that are defined in the element's inline style attribute. See the CSS Properties Reference for a list of the CSS properties accessible via style. The style property has the same (and highest) priority in the CSS cascade as an inline style declaration set via the style attribute.

Upvotes: 2

Yamada
Yamada

Reputation: 723

Actually your dropdown-content has no style within it at the beginning, it has a css associated to it. Just declare the display: none on the declaration and it will work as expected.

#dropbtn {
    background-color: #4CAF50;
    color: white;
    padding: 16px;
    font-size: 16px;
    border: none;
    cursor: pointer;
}

#dropdown {
    position: relative ;
    display: inline-block;
}

#dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

#dropdown-content a {
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
}

#dropdown-content a:hover {background-color: #f1f1f1}

/*#dropdown:hover #dropdown-content {
    display: block;
}*/

#dropdown:hover #dropbtn {
    background-color: #3e8e41;
}
<h2>Dropdown Menu</h2>
<p>Just a simple menu with link list</p>

<div id="dropdown">
  <button id="dropbtn" onclick="myFunction()">Dropdown</button>
  <div id="dropdown-content" style="display: none">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>
<script>

function myFunction() {
if (document.getElementById('dropdown-content').style.display == "none") 
         {document.getElementById('dropdown-content').style.display = "block";}
else {document.getElementById('dropdown-content').style.display = "none";}
    
    
}

</script>

Upvotes: 2

E. Sundin
E. Sundin

Reputation: 4181

The style property of the HTML element is not derived from the css styles applied to the element. So you're not accessing your #dropdown-content when you access style.display. Instead what you might do is have a css class that you add or removing depending on it's state.

Example adopted from your code:

#dropbtn {
  background-color: #4CAF50;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

#dropdown {
  position: relative;
  display: inline-block;
}

.hide {
  display: none;
}

#dropdown-content {
  position: absolute;
  background-color: #f9f9f9;
  min-width: 160px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}

#dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

#dropdown-content a:hover {
  background-color: #f1f1f1
}


/*#dropdown:hover #dropdown-content {
    display: block;
}*/

#dropdown:hover #dropbtn {
  background-color: #3e8e41;
}
<h2>Dropdown Menu</h2>
<p>Just a simple menu with link list</p>

<div id="dropdown">
  <button id="dropbtn" onclick="myFunction()">Dropdown</button>
  <div id="dropdown-content" class="hide">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>
<script>
  function myFunction() {
    let element = document.getElementById('dropdown-content');
    if (element.classList.contains('hide')) {
      element.classList.remove('hide')
    } else {
      element.classList.add('hide')
    }


  }
</script>

Upvotes: 1

K. P.
K. P.

Reputation: 561

Just replace none with block and block with none in the function, that's what you need.

Upvotes: 0

Related Questions