Martin
Martin

Reputation: 143

Show/Hide multiple Divs with same class name (javascript)

I've searched for same questions and found only jQuery solutions but I'd like to make it using JS only.

I have multiple divs with same class name and multiple a tags. I want the info show up when user press on a element associated with div.

Here's my function. I've created 2 loops: one for a elements and second is for divs.

function toggle() {
  	var ele = document.getElementsByClassName("toggleText");
  	var btn = document.getElementsByClassName("displayText");
    for(var i=0; i<btn.length; i++){
      for(var j=0; j<ele.length; j++){
    btn[i].onclick = function(){
  	if(ele[j].style.display == "none") {
      		ele[j].style.display = "block";

    	}
  	else {
  		ele[j].style.display = "block";

  	}
  }}}}
.displayText {
  display: none;
}
    <a class='toggleText' href="javascript:toggle();">Show1</a>
    <div class='displayText'>
      Text1
    </div>
    <a class='toggleText' href="javascript:toggle();">Show2</a>
    <div class='displayText'>
      Text2
    </div>
    <a class='toggleText' href="javascript:toggle();">Show3</a>
    <div class='displayText'>
      Text3
    </div>
    <a class='toggleText' href="javascript:toggle();">Show4</a>
    <div class='displayText'>
      Text4
    </div>

What's wrong with my code?

Upvotes: 1

Views: 4878

Answers (2)

zer00ne
zer00ne

Reputation: 43863

EDIT

@cirix has brought to my attention that my original code breaks because of the use of nextElementSibling without the necessary precautions to terminate the sibling chain. As it was before the edit if the last div was clicked it nextElementSibling would report a null since the last element would never have a next sibling (that's what makes last ...last).

There are 2 changes:

  1. Added an extra condition to ensure that the only event.targets dealt with are <a>nchors, thereby fixing the issue.
  2. Removed classList.add/remove and replaced them with classList.toggle(), that's an improvement, not a fix.

Use event delegation by wrapping all of your elements in one element. Then register the click event on it. With a little more setup you'll be able to control as many links as you want with just one eventListener. Details commented in Snippet.

SNIPPET

// Reference the parent element
var main = document.getElementById('main');

/* Register main to the click event 
|| when clicked ANYWHERE within main 
|| toggle() is called
*/
main.addEventListener('click', toggle, false);

function toggle(e) {
  /* Determine if the current element in the
  || event chain is the anchor that was 
  || clicked.
  */
  if (e.target !== e.currentTarget && e.target.nodeName === "A") {
    /* tgt is the clicked link
    || txt is the div that follows tgt
    */
    var tgt = e.target;
    var txt = tgt.nextElementSibling;
    // Toggle classes .on and .off
    txt.classList.toggle('on');
    txt.classList.toggle('off');
  }

}
.off {
  display: none;
}

.on {
  display: inline-block;
}
<section id='main'>
  <a class='toggleText' href="#/">Show1</a>
  <div class='displayText off'>
    Text1
  </div>
  <a class='toggleText' href="#/">Show2</a>
  <div class='displayText off'>
    Text2
  </div>
  <a class='toggleText' href="#/">Show3</a>
  <div class='displayText off'>
    Text3
  </div>
  <a class='toggleText' href="#/">Show4</a>
  <div class='displayText off'>
    Text4
  </div>
</section>

Upvotes: 1

cyr_x
cyr_x

Reputation: 14257

Add an EventListener to the parent container and detect which link was clicked and show/hide its next sibling div:

var linkClass = 'toggleText';
var textClass = 'displayText';
var visibilityClass = '-isVisible';
var container = document.querySelector('.container');
container && container.addEventListener('click', function(event) {
  var target = event.target;
  if(target.classList.contains(linkClass)) {
    var sibling = target.nextElementSibling;
    if(sibling && sibling.classList.contains(textClass)) {
      sibling.classList.toggle(visibilityClass, !sibling.classList.contains(visibilityClass));
    }
  }
});
.displayText {
  display: none;
}

.displayText.-isVisible {
  display: inline-block;
}
<div class="container">
  <a class='toggleText' href="javascript:void(0);">Show1</a>
  <div class='displayText'>
    Text1
  </div>
  <a class='toggleText' href="javascript:void(0);">Show2</a>
  <div class='displayText'>
    Text2
  </div>
  <a class='toggleText' href="javascript:void(0);">Show3</a>
  <div class='displayText'>
    Text3
  </div>
  <a class='toggleText' href="javascript:void(0);">Show4</a>
  <div class='displayText'>
    Text4
  </div>
</div>

Upvotes: 1

Related Questions