Home > Software engineering >  How do I hide the headline when the content underneath it is not visible
How do I hide the headline when the content underneath it is not visible

Time:02-23

I have an application in JavaScript with a very long list of 'Day-items', separated by a header specifying the month, like so:

<h3>January 2022</h3>
<div  data-visitors='1'>2022-01-01</div>
<div  data-visitors='0'>2022-01-02</div>
<div  data-visitors='1'>2022-01-03</div>
...etc until
<div  data-visitors='15'>2022-01-31</div>

<h3>February 2022</h3>
<div  data-visitors='0'>2022-02-01</div>
<div  data-visitors='1'>2022-02-02</div>
<div  data-visitors='19'>2022-02-03</div>
...etc until
<div  data-visitors='0'>2022-02-28</div>

<h3>March 2022</h3>
<div  data-visitors='0'>2022-03-01</div>
<div  data-visitors='11'>2022-03-02</div>
<div  data-visitors='5'>2022-03-03</div>
...etc until
<div  data-visitors='2'>2022-03-28</div>

The number of items are about 6.500 with some 200 headlines. I purposely do not write my code here as it is messy, and irrelevant in my opinion. It is the produced DOM that is interesting here.

Using filters in (vanilla) JavaScript, based on data-visitors value I change some divs to style.display='none'. For example, all divs with class 'item' with a data-visitors value below 15 will get a style.display='none'.

This will practically make the view of the html-file look like this

January 2022

February 2022

2022-02-03

March 2022

Here, I would like to hide "January 2022" and "March 2022" headlines (h3's) as there are no items visible for them (HTML-divs still exist but, as mentioned, with a display:none). In my application, this list ranges from 2004 to 2022 so there are a lot of empty months.

My question: How can I hide the month headers when there is no content underneath them visible any longer?

Due to how theses lists are being dynamically created:

What I can do: Add classes, ids, data-attributes etc to both month h3 headlines as well as divs

What I cannot do: Wrap h3 and the divs in a wrapping div, or add a wrapping div around all the <div class='item'>.

My conclusions, and I am not an experienced programmer in JavaScript: The divs are not children of the h3 so I cannot use anything like that. Siblings would not work either.

Thinking in pseudo-code, I would imagine putting a id='2022-02' on the h3-tag, and some data-attr-year-month-item='2022-02' on the div's. Then, query something like (this is just make-up-code):

if ((document.querySelectorAll("[attr-year-month-item='2022-02']").display=='none').length == (document.querySelectorAll("[attr-year-month-item='2022-02']").length)) {

document.getElementById('2022-02').style.display='none'

}

In other words, if the length of the divs that have style.display='none' equals the length of all the divs in that month, then the headline should be hidden.

What I would like help with is, how do I write this if-statement in vanilla JavaScript so that it works?

CodePudding user response:

You might traverse the items from the bottom to the top, checking if all of the group after h3 were hidden, then hide the h3:

let hideH3 = true;
[...document.querySelectorAll('.item')].reverse()
.forEach(i => {
  const hide = i.dataset.visitors < 15;
  hideH3 &= hide;
  if (hide) i.classList.add('hidden');
  const next = i.previousElementSibling;
  if (next.nodeName == 'H3') {
    if (hideH3) next.classList.add('hidden');
    else hideH3 = true;
  }
});
.hidden {display:none}
<h3>January 2022</h3>
<div  data-visitors='1'>2022-01-01</div>
<div  data-visitors='0'>2022-01-02</div>
<div  data-visitors='1'>2022-01-03</div>

<h3>February 2022</h3>
<div  data-visitors='0'>2022-02-01</div>
<div  data-visitors='1'>2022-02-02</div>
<div  data-visitors='19'>2022-02-03</div>
<div  data-visitors='0'>2022-02-28</div>

<h3>March 2022</h3>
<div  data-visitors='0'>2022-03-01</div>
<div  data-visitors='11'>2022-03-02</div>
<div  data-visitors='5'>2022-03-03</div>
<div  data-visitors='5'>2022-03-28</div>

CodePudding user response:

You have to set the visibility programatically so why not do this while you are at it? Something like

let element = document.getElementByID('firsth3');
let h3 = element;
while ( element.id != 'lastdiv' ) {
  element = element.nextElementSibling;
  if ( element.tagName == 'H3' ) {
    h3 = element;
  } else if ( element.dataset.visitors > 15 ) {
    element.styyle.display = 'block';
    h3.style.display = 'block';
  }
}

where you give everything a display: none initially and mark the first and last elements with ids.

  • Related