0

I'm trying to sum a list of values from HTML elements, but I want to EXCLUDE values are that hidden using pure JS.

HTML:

<div class="grams">1</div>
<div style="display: none;">
  <div class="grams">2</div>
</div>
<div class="milligrams">100</div>
<div class="milligrams">2</div>
<br>
<div>Total:</div>
<div class="servings"></div>

JS:

window.addEventListener('load', function() {
  let gramdivs = document.getElementsByClassName("grams");
  let milligramdivs = document.getElementsByClassName("milligrams");
  var total = 0;
  for (let item of gramdivs) {
    let itemPrice=parseFloat(item.textContent);
    total += itemPrice;
  }
  for (let item of milligramdivs) {
    let itemPrice=parseFloat(item.textContent);
    total = total + itemPrice / 1000;
  }
  document.getElementsByClassName("servings")[0].innerText = total.toFixed(3);
})

https://jsfiddle.net/smhok7yd/2/

In the JS Fiddle, you can see that all the numbers are being added, including the hidden one.

The correct output should be 1.102.

Please note that I cannot change the hierarchy of the HTML.

I am relatively new to JS and have been trying to find a solution all day.

3 Answers3

1

When iterating over elements, check to see if their offsetParent is null - if so, they're not visible:

const getClassValues = (className, multiplier = 1) => [...document.getElementsByClassName(className)]
  .filter(elm => elm.offsetParent !== null)
  .reduce((a, b) => a + (b.textContent * multiplier), 0);

document.querySelector('.servings').textContent = (
  getClassValues('grams') + getClassValues('milligrams', 0.001)
);
<div class="grams">1</div>
<div style="display: none;">
  <div class="grams">2</div>
</div>
<div class="milligrams">100</div>
<div class="milligrams">2</div>
<br>
<div>Total:</div>
<div class="servings"></div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    If the code isn't working, please post a [MCVE] in the question itself - the code in my answer looks fine to me, press "Run Code Snippet" to see it in action, I don't have any idea what your site is doing – CertainPerformance Oct 03 '20 at 02:16
  • The issue when that the script was loading before the user when through the questionnaire. Thanks! – Jonathan Buckley Oct 03 '20 at 17:26
0

If you set display: none; on the specific grams div you can check for the property before adding it to the total:

https://jsfiddle.net/et6wzph2/28/

Emilio
  • 389
  • 1
  • 8
0

function isVisible(e) {
  return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );
}

window.addEventListener('load', function() {
  let gramdivs = document.getElementsByClassName("grams");
  let milligramdivs = document.getElementsByClassName("milligrams");
  let total = 0;
  
  for (let item of gramdivs) {
    if(!isVisible(item)) continue;
    
    let itemPrice = parseFloat(item.textContent);
    total += itemPrice;
  }
  
  for (let item of milligramdivs) {
    if(!isVisible(item)) continue;
  
    let itemPrice = parseFloat(item.textContent);
    total = total + itemPrice / 1000;
  }
  document.getElementsByClassName("servings")[0].innerText = total.toFixed(3);
})
<div class="grams">1</div>
<div style="display: none;">
  <div class="grams">2</div>
</div>
<div class="milligrams">100</div>
<div class="milligrams">2</div>
<br>
<div>Total:</div>
<div class="servings"></div>
num8er
  • 18,604
  • 3
  • 43
  • 57
  • Just like the other solution it doesn't seem to be working when I put it into practice. I don't see what is different about the real version that is causing it to fail. It for the questionnaire on this page: bws-temp1.com/gamer-drink. If you go through it and select no for all your answers, where I want to do the calculation is on the ingredient summary page. The output is 0 with this code. – Jonathan Buckley Oct 03 '20 at 02:12
  • @JonathanBuckley depends how You're calling it. Since this one runs on window load. But in Your design there is not window load. So You've wrap it to function and call it at the end of form to calculate. – num8er Oct 03 '20 at 02:15