devofash
devofash

Reputation: 328

Accordion header not working when clicked

Hoping someone can help. Below is a javascript accordion. It works just the way I want for most part. See JS Fiddle below, accordion opens up when clicking on the red background however, I need it to open when clicked anywhere (red and blue). It's probably simple but can't work out why it doesn't work, would apppreciate some assistance.

https://jsfiddle.net/xgjmnpt4/

<div class="a-btn" style="background:red">

  <span style="left: 0"></span>

  <div class="row is-vertical-align" style="background:blue">

    <div class="col-4">

      cards
    </div>

    <div class="col-2 text-center">
      1
    </div>

    <div class="col-2 text-center">
      20
    </div>

    <div class="col-2 text-center">
      50
    </div>

    <div class="col-2 text-center">
      100
    </div>

  </div>

</div>

<div class="a-panel">

  <div class="row pb-2">

    Lorem Ipsum 
  </div>

  <div class="row">

    <div class="col-4">

      Card

    </div>

    <div class="col-4">

      cards

    </div>

  </div>

</div>
function initAcc(elem, option){
    document.addEventListener('click', function (e) {
        if (!e.target.matches(elem+' .a-btn')) return;
        else{
            if(!e.target.parentElement.classList.contains('active')){
                if(option==true){
                    var elementList = document.querySelectorAll(elem+' .a-container');
                    Array.prototype.forEach.call(elementList, function (e) {
                        console.log(elementList);
                        e.classList.remove('active');
                    });
                }            
                e.target.parentElement.classList.add('active');
            }else{
                e.target.parentElement.classList.remove('active');
            }
        }
    });
}

initAcc('.accordion', true);

.accordion {
    width: 100%;
    height: auto;
}
.accordion .a-container {
    width: 100%;
    padding-bottom: 5px;
}
.accordion .a-container .a-btn {
    margin: 0;
    position: relative;
    padding: 15px 60px 15px 30px;
    width: 100%;
    color: #191919;
    font-weight: 400;
    display: block;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.3s ease-in-out;
    border-radius: 0px;
    border: 1px solid rgba(211, 231, 235, 1);
    font-size: 1.6rem;

    font-family: sans-serif;
    color: #333;
}
.accordion .a-container .a-btn span {
    display: block;
    position: absolute;
    pointer-events: none;
    height: 2.4rem;
    width: 2.4rem;
    right: 2rem;
    padding-left: 0.5rem;
    border-radius: 2rem;
    top: 1.8rem;
}
.accordion .a-container .a-btn span:after {
    content: '';
    width: 1.4rem;
    height: 0.3rem;
    border-radius: 0.2rem;
    background-color: #333;
    position: absolute;
    top: 6px;
}
.accordion .a-container .a-btn span:before {
    content: '';
    width: 1.4rem;
    height: 0.3rem;
    border-radius: 0.2rem;
    background-color: #333;
    position: absolute;
    top: 0.6rem;
    transform: rotate(90deg);
    transition: all 0.3s ease-in-out;
}
.accordion .a-container .a-panel {
    width: 100%;
    color: #191919;
    opacity: 0;
    height: 0;
    overflow: hidden;
    padding: 0px 10px;
    border: 1px solid rgba(211, 231, 235, 1);
    border-top: 0;
}
.accordion .a-container.active .a-btn {
    color: #191919;
}
.accordion .a-container.active .a-btn span::before {
    transform: rotate(0deg);
}
.accordion .a-container.active .a-panel {
    padding: 30px;
    opacity: 1;
    height: auto;
}

EDIT: Below answer from Phoenix works, however not with multiple accordions. Would be great if someone could assist please.

Thanks.

Upvotes: 0

Views: 505

Answers (2)

Phoenix1355
Phoenix1355

Reputation: 1652

Instead of adding the event listener to the document, add it directly to the button instead. This will automatically target all children of the button as well, allowing you to click the blue area too.

I also cleaned up the way you add and remove the active class from the container. There is no need to use a large selector each time to target the container from the clicked element.

Snippet:

function initAcc(elem, option) {
    var container = document.querySelector(elem + " .a-container");
    var button = container.querySelector(".a-btn");
    
    button.addEventListener('click', function (e) {
      if(!container.classList.contains('active')) {
        if(option==true) {
            container.classList.remove('active');
        }
        container.classList.add('active');
      } else {
        container.classList.remove('active');
      }
    });
}

initAcc('.accordion', true);
 .accordion {
     width: 100%;
     height: auto;
}
 .accordion .a-container {
     width: 100%;
     padding-bottom: 5px;
}
 .accordion .a-container .a-btn {
     margin: 0;
     position: relative;
     padding: 15px 60px 15px 30px;
     width: 100%;
     color: #191919;
     font-weight: 400;
     display: block;
     font-weight: 500;
     cursor: pointer;
     transition: all 0.3s ease-in-out;
     border-radius: 0px;
     border: 1px solid rgba(211, 231, 235, 1);
     font-family: sans-serif;
     color: #333;
}
 .accordion .a-container .a-btn span {
     display: block;
     position: absolute;
     pointer-events: none;
     height: 2.4rem;
     width: 2.4rem;
     right: 2rem;
     padding-left: 0.5rem;
     border-radius: 2rem;
     top: 1.8rem;
}
 .accordion .a-container .a-btn span:after {
     content: '';
     width: 1.4rem;
     height: 0.3rem;
     border-radius: 0.2rem;
     background-color: #333;
     position: absolute;
     top: 6px;
}
 .accordion .a-container .a-btn span:before {
     content: '';
     width: 1.4rem;
     height: 0.3rem;
     border-radius: 0.2rem;
     background-color: #333;
     position: absolute;
     top: 0.6rem;
     transform: rotate(90deg);
     transition: all 0.3s ease-in-out;
}
 .accordion .a-container .a-panel {
     width: 100%;
     color: #191919;
     opacity: 0;
     height: 0;
    /*max-height: 0;
    */
     overflow: hidden;
     padding: 0px 10px;
     border: 1px solid rgba(211, 231, 235, 1);
     border-top: 0;
}
 .accordion .a-container.active .a-btn {
     color: #191919;
}
 .accordion .a-container.active .a-btn span::before {
     transform: rotate(0deg);
}
 .accordion .a-container.active .a-panel {
     padding: 30px;
     opacity: 1;
     height: auto;
}
 
<div class="accordion">


  <div class="a-container">

    <div class="a-btn" style="background:red">

      <span style="left: 0"></span>

      <div class="row is-vertical-align" style="background:blue">

        <div class="col-4">

          cards
        </div>

        <div class="col-2 text-center">
          1
        </div>

        <div class="col-2 text-center">
          20
        </div>

        <div class="col-2 text-center">
          50
        </div>

        <div class="col-2 text-center">
          100
        </div>

      </div>

    </div>

    <div class="a-panel">

      <div class="row pb-2">

        Lorem Ipsum 
      </div>

      <div class="row">

        <div class="col-4">

          Card

        </div>

        <div class="col-4">

          cards

        </div>

      </div>

    </div>

  </div>




</div>

Upvotes: 1

Tasos
Tasos

Reputation: 2036

It is caused by this line:

if (!e.target.matches(elem+' .a-btn')) return;

The blue container has class row is-vertical-align. In order to make it work you need to include this class in your if-statement that I mentioned.

Note: Adding the listener to the document is not a good practice. You should add the same event listener for "click" on both your red and blue elements.

Upvotes: 1

Related Questions