1

When a button is clicked I want to change the display of all classes to display: hide; and reverse them on

CSS:

<style>
 div.inactive {
   display: block;
 }
</style>

HTML:

<button onclick="hideInactive()">Show/hide</button>

<div class="inactive">DIV 1: inactive</div>
<p class="inactive">DIV 2: inactive</p>
<ul>
  <li class="inactive">
    List item 1: Inactive
  </li>
  <li>
    List item 2: Active
  </li>
</ul>

JS:

<script>
function hideInactive() {
    var x = document.getElementsByClassName('.inactive');
    if (x.style.display === "none") {
        x.style.display = "block";
    } else {
        x.style.display = "none";
    }
}
</script>

I have tried to select all classes in this way instead:

var x = document.querySelectorAll(".inactive");

And I have tried to loop over every class:

function hideInactive() {
    var x = document.querySelectorAll(".inactive");
    for (var i = 0; i < x.length; i++) {
        if (x.style.display === "none") {
            x.style.display = "block";
        } else {
            x.style.display = "none";
        }
    }
}
suverenia
  • 79
  • 6
  • 1
    The `getElementsByClassName` code doesn’t work; see [What do querySelectorAll and getElementsBy\* methods return?](https://stackoverflow.com/q/10693845/4642212). Inline event handlers like `onclick` are [not recommended](https://stackoverflow.com/q/11737873/4642212). They are an [obsolete, hard-to-maintain and unintuitive](https://stackoverflow.com/a/43459991/4642212) way of registering events. Always [use `addEventListener`](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Inline_event_handlers_—_dont_use_these) instead. – Sebastian Simon Dec 27 '20 at 05:16
  • 2
    Also, you don't put `.` at the beginning of the class when calling `getElementsByClassName`. That's part of CSS selector syntax. You can use it with `querySelectorAll` – Barmar Dec 27 '20 at 05:20
  • 1
    In your `querySelectorAll` approach you’re looping over the result, seemingly because you know that `querySelectorAll` returns a `NodeList`, but for some reason you’re not utilizing the loop at all. Why are you not using `i` in the loop body? Another potential issue is [Button to show/hide div has to be pressed twice](https://stackoverflow.com/q/44837679/4642212). Instead, use the [`classList` API](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList#Methods) to toggle a class; use iteration methods instead of `for` loops. – Sebastian Simon Dec 27 '20 at 05:21
  • 1
    thank you guys... I have a lot to learn. I will study your suggestions. – suverenia Dec 27 '20 at 05:35
  • 1
    @suverenia I strongly recomment you to read up on the "browser pixel-pipeline". https://developers.google.com/web/fundamentals/performance/rendering .. You'll thank me later. – zergski Dec 27 '20 at 05:43

2 Answers2

1

Try adding a class to the parent or grand-parent of the element you want to affect. Then simply have a rule in your css..

.hide-class .target-element { visibility: hidden; } .. Note that using visibility is more performant as the browser doesn't recalculate the Layout.

Then if you want to display the element again, just remove the class from parent.. This way is performant and easily managable.

@sourav wanted an example.. so

CSS

/* here we hide the element with the '.foo' class when we add the '.hide-foo' class to body */
body.hide-foo .foo {
   visibility: hidden;
}

/* this makes the child visibile, even though the parent is hidden. Handy! */
.bar {
   visibility: visible;
}

JS

const body = document.body;
body.classList.add('hide-foo');

HTML

   <body>
      <!-- this is hidden -->
      <div class="foo"></div>
      <!-- this is visible -->
      <div></div>
      <!-- this is hidden -->
      <div class="foo">
         <!-- and this is visible even though the parent is hidden -->
        <div class="bar"></div>
      </div>
   </body>

Hope this helps to understand :)

zergski
  • 793
  • 3
  • 10
  • what if elements are sibling rather than parent? what if I want some children inside the parent to stay visible while to hide some children? – sourav satyam Dec 27 '20 at 05:47
  • 1
    @souravsatyam You can go as far a the root element with this method.. i.e. when adding a class to body ( `document.body.classList.add('hide-foo')` ) and you have a rule in your CSS that's similar to `body.hide-foo .foo { visibility: hidden }` the browser will hide all elements with the class `.foo` located in the `body`. Regardless if it's a sibling, child or cousin... This way there are no extra calculations, loops and only one write to DOM. Also extra efficient if you make use of CSS variables.. It's all in the structure. – zergski Dec 27 '20 at 05:59
  • `document.body.classList.add('hide-foo')` this will add `hide-foo` class to body. Even if I add `visibility: hidden` in foo class than while removing the class I will have to iterate. foo is to be added only with certain class. It will be great if you can provide a practical example without iterating the element. – sourav satyam Dec 27 '20 at 06:06
  • @souravsatyam My friend. Try to listen to what I'm saying .. When you add `hide-foo` class body AND you have a class ( in this case `.foo`) written after separated by a SPACE. The browser apllies the `visibility: hidden` property to all elements with the class of `.foo` INSIDE the body. The body itself is unaffected. I've given an example of the exact amount of code required for this task in my previous comment. That's the beuty of it.. – zergski Dec 27 '20 at 06:15
  • 1
    Ok! I got your point. Means you will keep toggle `hide-foo` class in the body on button click and those which have `foo` class will toggle visibility. yes, better approach. Will try. – sourav satyam Dec 27 '20 at 06:26
  • @sourav Yepp! you got it! =) – zergski Dec 27 '20 at 06:28
1

document.getElementsByClassName returns an HTMLCollection, so your hideInactive function is checking style on an HTMLCollection. Iterate the array and check for each element instead.

function hideInactive() {
  var x = document.getElementsByClassName('inactive');

  console.log(x.length);

  for (let i = 0 ; i < x.length; i++) {
    if (x[i].style.display === "none") {
      x[i].style.display = "block";
    } else {
      x[i].style.display = "none";
    }
  }
}
<button onclick="hideInactive()">Show/hide</button>

<div class="inactive">DIV 1: inactive</div>
<p class="inactive">DIV 2: inactive</p>
<ul>
  <li class="inactive">
    List item 1: Inactive
  </li>
  <li>
    List item 2: Active
  </li>
</ul>
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
sourav satyam
  • 980
  • 5
  • 11