skip to Main Content

I have a class named view under the "five" div. And I have two children named rView, siblings of view parents. Now if I want to fire the click event on the view class which is in cc1.fir & target all rView classes, all rView classes are fired either it is in cc1.fir or it is in cc1.sec. Also, when I want to click on view which is in cc1.sec event is not fired.

I want that if user click on cc1.fir then all rView classes should be displayed, not just the rView present in cc1.sec. And, this click event should work for all cc1 classes.

view = document.getElementsByClassName('view');
rView = document.querySelectorAll('.rView');

for (var i = 0; i < view.length; i++) {
    view[i].addEventListener('click', () => {
        rView.forEach(element => {
            element.classList.toggle('View_active');
        });
    });
}
.rView {
  display: none;
}

.View_active {
  display: block;
}
<div class="section">
  <div class="fir cc1">
    <div class="cc2">
      <div class="cc3">
        <div class="cc4">
          <div class="cc5">
            <p class="view">view</p>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="text rView">
    <p>Hello-down</p>
  </div>
  <div class="text rView">
    <p>Hello-down</p>
  </div>

  <div class="sec cc1">
    <div class="cc2">
      <div class="cc3">
        <div class="cc4">
          <div class="cc5">
            <p class="view">view</p>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="text rView">
    <p>Hello-down</p>
  </div>
  <div class="text rView">
    <p>Hello-down</p>
  </div>
</div>

2

Answers


  1. This would work for your use case:

    view = document.getElementsByClassName('view');
    
    for (var i = 0; i < view.length; i++) {
        view[i].addEventListener('click', (e) => {
            expand = e.currentTarget.getAttribute("data-expand");
            rView = document.querySelectorAll('.rView[data-expand="'+expand+'"]');
            rView.forEach(element => {
                element.classList.toggle('View_active');
            });
        });
    }
    .rView {
      display: none;
    }
    
    .View_active {
      display: block;
    }
    <div class="section">
      <div class="fir cc1">
        <div class="cc2">
          <div class="cc3">
            <div class="cc4">
              <div class="cc5">
                <p class="view" data-expand="1">view</p>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="text rView" data-expand="1">
        <p>Hello-down</p>
      </div>
      <div class="text rView" data-expand="1">
        <p>Hello-down</p>
      </div>
    
      <div class="sec cc1">
        <div class="cc2">
          <div class="cc3">
            <div class="cc4">
              <div class="cc5">
                <p class="view" data-expand="2">view</p>
              </div>
            </div>
          </div>
        </div>
      </div>
    
      <div class="text rView" data-expand="2">
        <p>Hello-down</p>
      </div>
      <div class="text rView" data-expand="2">
        <p>Hello-down</p>
      </div>
    </div>
    Login or Signup to reply.
  2. Also, when I want to click on view which is in cc1.sec event is not fired.

    This is because you attach an event listener to the very first .view selector that will appear in the DOM.

    To target all views:

    1. Select all views in the DOM using querySelectorAll:
    2. Attach the click listener to each view using forEach loop.

    Apart from that, the code is not well-written. You should instead:

    a) Use <button element with onclick <button onclick="toggleActiveView()">view</button>. Div has no out-of-the-box accessibility support. It’s generally a bad idea to use it for user interactions, unless you provide all accessibility features by yourself.

    or

    b) There is such thing in JS as Bubbling and capturing so you can wrap all your buttons with a div and catch all the events there. But make sure you check that the click was on a button and not on the div.

    const wrapper = document.getElementById('wrapper');
    
    wrapper.addEventListener('click', (event) => {
      const isButton = event.target.nodeName === 'BUTTON';
      if (!isButton) {
        return;
      }
    
      console.dir(event.target.id);
    })
    

    Additionally, you don’t need to iterate over all rView elements to toggle their visibility. Instead, you could leverage data attribute of the parent.

    Here’s the improved version that:

    1. Uses the data-accordion-trigger data attribute to verify if the trigger has been clicked.
    2. Does not iterate over elements. Instead, uses event-bubbling for the #accordion wrapper.
    3. Uses data-accordion-expanded to indicate that rView should be visible.
    <html lang="en">
      <head>
        <style>
          #accordion[data-accordion-expanded] .rView {
            display: block;
          }
          .rView {
            display: none;
          }
        </style>
      </head>
      <body>
        <div class="section">
          <div id="accordion">
            <div class="fir cc1">
              <div class="cc2">
                <div class="cc3">
                  <div class="cc4">
                    <div class="cc5">
                      <button class="view" data-accordion-trigger="true">
                        view
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
    
            <div class="text rView">
              <p>Hello-down</p>
            </div>
            <div class="text rView">
              <p>Hello-down</p>
            </div>
    
            <div class="sec cc1">
              <div class="cc2">
                <div class="cc3">
                  <div class="cc4">
                    <div class="cc5">
                      <button class="view" data-accordion-trigger="true">
                        view
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
    
            <div class="text rView">
              <p>Hello-down</p>
            </div>
            <div class="text rView">
              <p>Hello-down</p>
            </div>
          </div>
        </div>
    
        <script>
          const accordion = document.querySelector("#accordion");
    
          accordion.addEventListener("click", (event) => {
            const isTrigger = event.target.hasAttribute("data-accordion-trigger");
            if (isTrigger) {
              toggleAccordion();
            }
          });
    
          function toggleAccordion() {
            accordion.toggleAttribute("data-accordion-expanded");
          }
        </script>
      </body>
    </html>

    EDIT:

    If you only want to expand a group of elements for the given button, you need to edit the code accordingly:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>HTML + CSS</title>
        <style>
          #accordion div[data-accordion-group][data-accordion-expanded] .rView {
            display: block;
          }
          .rView {
            display: none;
          }
        </style>
      </head>
      <body>
        <div class="section">
          <div id="accordion">
            <div data-accordion-group="">
              <div class="fir cc1">
                <div class="cc2">
                  <div class="cc3">
                    <div class="cc4">
                      <div class="cc5">
                        <button class="view" data-accordion-trigger="">view</button>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
    
              <div class="text rView">
                <p>Hello-down</p>
              </div>
              <div class="text rView">
                <p>Hello-down</p>
              </div>
            </div>
    
            <div data-accordion-group="">
              <div class="sec cc1">
                <div class="cc2">
                  <div class="cc3">
                    <div class="cc4">
                      <div class="cc5">
                        <button class="view" data-accordion-trigger="">view</button>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
    
              <div class="text rView">
                <p>Hello-down</p>
              </div>
              <div class="text rView">
                <p>Hello-down</p>
              </div>
            </div>
          </div>
        </div>
    
        <script>
          const accordion = document.querySelector("#accordion");
    
          accordion.addEventListener("click", (event) => {
            const isTrigger = event.target.hasAttribute("data-accordion-trigger");
            if (isTrigger) {
              const groupElement = event.target.closest("[data-accordion-group]");
              toggleAccordionGroup(groupElement);
            }
          });
    
          function toggleAccordionGroup(groupElement) {
            groupElement.toggleAttribute("data-accordion-expanded");
          }
        </script>
      </body>
    </html>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search