Mark Messa
Mark Messa

Reputation: 470

Javascript inline loop through getElementsByClassName

Consider the following simplified html code:

<html>
    <head>
        <style>
            .opts {display: none}
        </style>
    </head>

    <body onload = "list = document.getElementsByClassName('opts')">

        <form>
            <ul>
                <li>
                    <label>Show Options?</label>
                    <input type="radio" onclick="list[0].style.display = 'block'; list[1].style.display = 'block'; list[2].style.display = 'block';">yes<br>
                    <input type="radio" onclick="list[0].style.display = 'none'; list[1].style.display = 'none'; list[2].style.display = 'none';">no<br>
                </li>

                <li class="opts">
                    <label>Option 1</label>
                    <input type="text">
                </li>

                <li class="opts">
                    <label>Option 2</label>
                    <input type="text">
                </li>

                <li class="opts">
                    <label>Option 3</label>
                    <input type="text">
                </li>

                ... etc ...

            </ul>
        </form>

    </body>

</html>

Basically, it uses javascript to show or hide optional elements according to user onclick event.

Issue
Currently, for each element in getElementsByClassName there is a line setting 'manually' the display property:

list[0].style.display = 'block';
list[1].style.display = 'block';
list[2].style.display = 'block';

Is there a simpler way to do that? For example, something like:

list[All].style.display = 'block';

ps: of course this could be done via some for loop and an additional function declaration, but I'm looking for an easy inline js code (ie: no external js files)

Followup

Based on comments, there are two proposed ways to easily code this inline without external files:

1) spread syntax

[...list].forEach(el => el.style.display = 'block')

2) for loop new syntax

for (const x of list) x.style.display = "block";

Particularly, I've decided to use the for loop new syntax due to be easier to read then the spread syntax. However, since both ways are somewhat recent features of JavaScript, caution is advised for older browsers compatibility.

Upvotes: 1

Views: 1352

Answers (2)

RobG
RobG

Reputation: 147363

Consider toggling classes rather than directly setting display values. Also, for a straight binary selection, I'd just use a checkbox.

Iterating over an array using forEach isn't a lot of code, and accommodating older browsers is simple too:

function toggleOpts() {
  var opts = Array.from(document.querySelectorAll('.opts'));
  opts.forEach(function(opt) {
    opt.style.display = this.checked ? '' : 'none';
  }, this);
}
window.onload = function() {
  document.getElementById('optToggle').addEventListener('click', toggleOpts, false);
}
<title>Sample</title>
<form>
  <ul>
    <li>
      <label for="optToggle">Show Options?
        <input type="checkbox" id="optToggle" checked>yes
      </label>
    </li>

    <li class="opts">
      <label>Option 1</label>
      <input type="text">
    </li>

    <li class="opts">
      <label>Option 2</label>
      <input type="text">
    </li>

    <li class="opts">
      <label>Option 3</label>
      <input type="text">
    </li>
  </ul>
</form>

Upvotes: 0

user8897421
user8897421

Reputation:

// setup for the environment
const All = Symbol("All");
const setter = {set: function(fn) {
  for (var i = 0; i < this.length; i++) {
    fn(this[i], i, this);
  }
}};
Object.defineProperty(HTMLCollection.prototype, All, setter);
Object.defineProperty(NodeList.prototype, All, setter);




// Your code
const list = document.getElementsByClassName('opts')

list[All] = x => x.style.fontWeight = "bold";
<form>
  <ul>
    <li>
      <label>Show Options?</label>
      <input type="radio" onclick="list[0].style.display = 'block'; list[1].style.display = 'block'; list[2].style.display = 'block';">yes<br>
      <input type="radio" onclick="list[0].style.display = 'none'; list[1].style.display = 'none'; list[2].style.display = 'none';">no<br>
    </li>

    <li class="opts">
      <label>Option 1</label>
      <input type="text">
    </li>

    <li class="opts">
      <label>Option 2</label>
      <input type="text">
    </li>

    <li class="opts">
      <label>Option 3</label>
      <input type="text">
    </li>

    ... etc ...

  </ul>
</form>

Upvotes: 1

Related Questions