0

I want to sum the numbers and print them out in the span, i tried with innerHTML but as it is a string i can't, i tried parseInt, parseFloat, Number and nothing. For all the checkbox checked i want the sum of it's values into the span and those who are not checked i don't want them to get summ in the span

(i reduced the table and a lot of numbers because it's so long for putting it in here, so imagine that i want to sum a lot of total numbers)

const offersCheckbox = document.querySelectorAll("#checkbox-offers");
const recalculateText = document.querySelector(".recalculate-text");
const checkboxTotal = document.querySelectorAll("#checkbox-total");
let total = 0;

for (let i = 0; i < offersCheckbox.length; i++) {
  offersCheckbox[i].addEventListener("click", (e) => {
    if (offersCheckbox[i].checked === true) {
      recalculateText.innerHTML = "recalculate invoice total";
    } else {
      recalculateText.innerHTML = "";
    }
  });
}
<table>
  <tr>
    <tr>
      <td>
        <input type="checkbox" name="checkbox" id="checkbox-offers" value="2,434.38" />
        <td>
          <div class="price-container text-bold" id="checkbox-total">
            <b>$</b>2,434.38
          </div>
        </td>
    </tr>

    <tr>
      <td>
        <input type="checkbox" name="checkbox" id="checkbox-offers" value="76.69" />
      </td>
      <td>
        <div class="price-container text-bold" id="checkbox-total">
          <b>$</b>76.69
        </div>
      </td>
    </tr>
</table>

<span class="recalculate-text text-right text-underline"></span>
ikiK
  • 6,328
  • 4
  • 20
  • 40
Simon
  • 55
  • 10
  • 2
    What did you try? SO is not free code writing or evaluating service, share your attainment and we will fix it. Also make [mre] by pressing <> button in editor and creating an snippet, it will greatly increase chance of you getting an answer. Also just to point out, ALL you need to know about how to do this IS already answered here or on google. So put some effort in asking a question and trying to solve this. Welcome to SO, – ikiK Mar 03 '21 at 20:47
  • 1
    HTML element id's MUST be unique, you need to change your `id` attributes of each input field – AGE Mar 03 '21 at 21:00
  • i changed the id's for classes, but that doesn't fix my problem, there is any way to do it? – Simon Mar 03 '21 at 21:09
  • that is because your jquery selector is incorrect, there are a few answers already you can consider looking into – AGE Mar 03 '21 at 21:23

4 Answers4

0

As per fixing the code you already have:

  1. id's are unique, so use checkbox-offers as class and querySelectorAll as you already have loop for it
  2. Js numbers have no , in them so you need to clear them to get a number capable of math functions
  3. in your loop you have (e) witch indicates event, so use e.target to target that event and filed and take its value.
  4. with offersCheckbox[i] you just addEventListener and from then on you use e.target
  5. you need to convert value to a number with parseFloat(num)
  6. When inserting value you need to take into account already added value if there is one, if not parse is as 0, if there is some parse it as number and add addition to it:
  7. if you want to add back , as thousandth separator to result, that has plenty of answers here on SO, just search them.

recalculateText.innerHTML = (parseFloat(recalculateText.innerHTML || 0) + num2)

const offersCheckbox = document.querySelectorAll(".checkbox-offers");
const recalculateText = document.querySelector(".recalculate-text");

let total = 0;

for (let i = 0; i < offersCheckbox.length; i++) {
  offersCheckbox[i].addEventListener("click", (e) => {
   
    let num = e.target.value.split(",").join("")
    let num2 = parseFloat(num)

    if (e.target.checked === true) {
      recalculateText.innerHTML = (parseFloat(recalculateText.innerHTML || 0) + num2)
    } else {
      recalculateText.innerHTML = "";
    }
  });
}
<table>
  <tr>
    <tr>
      <td>
        <input type="checkbox" class="checkbox-offers" name="checkbox" value="2,434.38" />
        <td>
          <div class="price-container text-bold" id="checkbox-total">
            <b>$</b>2,434.38
          </div>
        </td>
    </tr>

    <tr>
      <td>
        <input type="checkbox" class="checkbox-offers" name="checkbox" value="76.69" />
      </td>
      <td>
        <div class="price-container text-bold" id="checkbox-total">
          <b>$</b>76.69
        </div>
      </td>
    </tr>
</table>

<span class="recalculate-text text-right text-underline"></span>

Useful links:

What do querySelectorAll and getElementsBy* methods return?

How to print a number with commas as thousands separators in JavaScript

What properties can I use with event.target?

How to convert a string to an integer in JavaScript?

ikiK
  • 6,328
  • 4
  • 20
  • 40
0

Please note you need to leverage the input field's event handler system, in this case onchange where each input field handles modifying the stored value of the sum of each price.

I did write a currency to number normalizer via regex, however I did not write a number to currency formatter, to re-format the total sum back to a currency. You will need to handle doing that yourself.

let sum = 0;

let addPrice = (elem) => {
  let value = parseFloat(elem.value.replace(/\$|,/g, ''), 2);
  
  elem.checked ? (sum += value) : (sum -= value);

  document.getElementById('result').innerHTML = sum;
};
<table>
  <tr>
    <tr>
      <td>
        <input type="checkbox" name="price" value="2,434.38" onchange="addPrice(this)" />
        <td>
          <div class="price-container text-bold">
            <b>$</b>2,434.38
          </div>
        </td>
    </tr>

    <tr>
      <td>
        <input type="checkbox" name="price" value="76.69" onchange="addPrice(this)" />
      </td>
      <td>
        <div class="price-container text-bold">
          <b>$</b>76.69
        </div>
      </td>
    </tr>
</table>

<div class="recalculate-text text-right text-underline">Total: <span id="result">0</span></div>
AGE
  • 3,752
  • 3
  • 38
  • 60
  • why for the love of God would you add jquery in snippet just for that last insert ?!? And jquery was not mentioned anywhere in question ;) – ikiK Mar 03 '21 at 21:41
  • 1
    @ikiK hmm that jQuery line be changed easily to a `document.getElementById`, update made for consistency – AGE Mar 03 '21 at 21:46
  • of course it can, and it should be :) I thouhgs it was just funny. After everything in vanilla js, insert with jquery, makes no sense. – ikiK Mar 03 '21 at 21:47
  • Thanks, btw I like your approach of using regex for this, but you will never find me doing it for simple things like this. Split.join is my way to go. Nice example nevertheless. there is also replaceAll. To make it even more redundant – ikiK Mar 03 '21 at 21:51
  • I understand your point. The currency formatter is another implementation hurdle for the person who asked the question to solve, I can provide a very good answer to that since I have built many myself, but the constraints usually are much more strict here (hence the straight forward regex). The problem with the question itself is what matters here. – AGE Mar 03 '21 at 21:55
  • Of coarse, it was just my 2 cents, cheers. – ikiK Mar 03 '21 at 21:57
0

I didnt change too much from your original code. See the comments to understand the changes I made and feel free to comment if you have additional questions.

const recalculateText = document.querySelector(".recalculate-text");
const checkboxContainer = document.querySelector("#checkbox-container");
let total = 0;

// Create a number formatter to print out on the UI - this is a better approach than regex IMO.
const formatter = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
});

//Notice the use of event delegation here - meaning I only added 1 single event handler to a single DOM element
//Read this blog for more on event delegation and why it's useful: https://davidwalsh.name/event-delegate
checkboxContainer.addEventListener('change', e => {
  //Also notice that I am listening for the change event, instead of the click event.
  //See here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event
  if (e.target.tagName == "INPUT") {
    const floatValue = parseFloat(e.target.value);
    if (e.target.checked) {
      total += floatValue;
    } else {
      total -= floatValue;
    }
  }

  recalculateText.innerHTML = formatter.format(total);
});
<!-- Notice I added a parent div to enable use to use event delegation technique -->
<!-- Also notice I removed element id attributes where they were not needed. Also be sure
to always use unique id values for every element - duplicate ids are not allowed, it will 
lead to bugs. If elements need to be considered part of the same "group" then you should use
the class attribute. -->
<div id="checkbox-container">
  <table>
    <tr>
      <tr>
        <td>
          <!-- Notice I removed the comma from the value attribute -->
          <input type="checkbox" name="checkbox" value="2434.38" />
          <td>
            <div class="price-container text-bold">
              <b>$</b>2,434.38
            </div>
          </td>
      </tr>

      <tr>
        <td>
          <input type="checkbox" name="checkbox" value="76.69" />
        </td>
        <td>
          <div class="price-container text-bold">
            <b>$</b>76.69
          </div>
        </td>
      </tr>
  </table>
</div>
<span class="recalculate-text text-right text-underline"></span>
Tom O.
  • 5,730
  • 2
  • 21
  • 35
  • "I didnt change too much from your original code." Well you should address if nothing else duplicate same ids... There is `document.querySelectorAll("#checkbox-offers");` on id, that is duplicate... And `querySelectorAll` to be even more precise. So the code it slef is wrong and needs addressing. – ikiK Mar 03 '21 at 21:43
  • This worked out for me, instead of using that formatter i used split(",").join("") and doing the event listener on the input not on the div container. Thanks everyone – Simon Mar 03 '21 at 21:52
-1
$('input[type="checkbox"]').change(function() {
    var checkArray = [];
    var total = 0;
    $("input:checkbox[name=checkbox]:checked").each(function(key){
      checkArray.push($(this).val());
  });
    if(checkArray.length !== 0) {
    total = checkArray.reduce(function(a, b){
                            return parseInt(a) + parseInt(b);
                            }, );
    $(".recalculate-text").text(total);
   }
});
Muneeb
  • 85
  • 1
  • 10
  • While answers like this can solve the problem they are not welcomed on SO, they need explanation so OP actuality learns something from them for next time. – ikiK Mar 03 '21 at 21:28