Bob Cooper
Bob Cooper

Reputation: 31

Trouble with JavaScript collection of document elements

I'm not sure if I'm on the wrong course altogether, or just missing a minor bit. I have a page that has sections, subsections, and subsubsections. The latter are elements that all share a common formatting:

<select id="SubSubFlood"  class='hidden'>
    <option></option>
</select>
<select id="SubSubHome"  class='hidden'>
    <option></option>
</select>

I can't name each one explicitly because they're dynamically generated, but they all start with "SubSub". I'm trying to create code that will change all of the SubSubs to class='hidden', then change the one I want to be visible to class='unhidden'. Here is my attempt:

function ShowSubSub(SelectID) {
    var SubSub = document.getElementsByTagName("Select");
    var item;
    for (item in SubSub) {
        if (item.ID.match(/SubSub.*/)) {            
            item.className = 'hidden';
        }
    }
    item = document.getElementById(SelectID);
    item.className = 'unhidden';
}

Where am I missing the boat? How do I get JavaScript to change every tag with an ID that starts with "SubSub" to class="hidden"?

Upvotes: 1

Views: 63

Answers (3)

Kamil Kiełczewski
Kamil Kiełczewski

Reputation: 92627

The problem is that getElementsByTagName returns HTMLCollection which "not work" with for-in, instead use

for (let i =0; i<SubSub.length; i++) {
    let item = SubSub[i];
    if (item.id.match(/SubSub.*/)) {            
        item.className = 'hidden';
    }
}

function ShowSubSub(SelectID) {
    var SubSub = document.getElementsByTagName("Select");
    console.log(SubSub);
    for (let i =0; i<SubSub.length; i++) {
        let item = SubSub[i];
        if (item.id.match(/SubSub.*/)) {            
            item.className = 'hidden';
        }
    }
    item = document.getElementById(SelectID);
    console.log(item);
    item.className = 'unhidden';
}

ShowSubSub('SubSubHome');
.hidden {
  background: red;
}

.unhidden {
  background: blue;
}
<select id="SubSubFlood" >
    <option></option>
</select>
<select id="SubSubHome"  >
    <option></option>
</select>

I also develop a little improvement to connexo solution:

function ShowSubSub(SelectID) 
{
      [...document.querySelectorAll('[id^="SubSub"]')].map(s => 
        s.id==SelectID ? s.className=('unhidden') : s.className=('hidden')
    )
}

ShowSubSub('SubSubHome');

   function ShowSubSub(SelectID) 
{
	  [...document.querySelectorAll('[id^="SubSub"]')].map(s => 
    	s.id==SelectID ? s.className=('unhidden') : s.className=('hidden')
    )
}

ShowSubSub('SubSubHome');
.hidden {
  background: red;
}

.unhidden {
  background: blue;
}
<select id="SubSubFlood" >
    <option></option>
</select>
<select id="SubSubHome"  >
    <option></option>
</select>

Upvotes: 0

connexo
connexo

Reputation: 56783

This replies to the question:

How do I get JavaScript to change every tag with an ID that starts with "SubSub" to class="hidden"?

[...document.querySelectorAll('[id^="SubSub"]')].forEach(section => section.className.add('hidden'))

will achieve just that.

So let's break that up:

  1. First of all use an attribute selector that matches all elements that have an id value starting with SubSub: [id^="SubSub"].

    Query the document for all of these: document.querySelectorAll('[id^="SubSub"]')

  2. Spread the NodeList you get to into an array using ... (spread operator):

    [...document.querySelectorAll('[id^="SubSub"]')]
    

    Alternatively, you could also use Array.from(iterable):

    Array.from(document.querySelectorAll('[id^="SubSub"]'))
    
  3. so it's cross-browser safe to use forEach on the result:

    [...document.querySelectorAll('[id^="SubSub"]')].forEach((section) => {})
    
  4. In that loop, simply add the classname to the classList:

    section.className.add('hidden')
    

Upvotes: 2

George
George

Reputation: 6739

SubSub will contain an array like object, so when you put it in a for each loop, you'll be enumerating it's properties, not the elements themselves. So item in the loop will not be the first select, it'll be 0. I suggest changing it to a normal for loop

function ShowSubSub(SelectID) {
  var SubSub = document.getElementsByTagName("Select");
  var item;
  for (var i =0; i < SubSub.length; i++) {
    if (SubSub[i].id.match(/SubSub.*/)) {
      SubSub[i].className = 'hidden';
    }
  }
  item = document.getElementById(SelectID);
  item.className = 'unhidden';
}

ShowSubSub('SubSubHome')
.hidden{

display:none;
}
<select id="SubSubFlood" class='hidden'>
  <option>Flood</option>
</select>
<select id="SubSubHome" class='hidden'>
  <option>Home</option>
</select>

P.S. is there any reason for having an unhidden class, can't you just remove the hidden class?

Upvotes: 5

Related Questions