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.