1

I'm trying to translate a pay and savings calculator I made in excel to a web page I can host on my website and access anywhere.

What I want is to have the values automatically update without the need of pressing a load of buttons.

I've done a bit of research and put together this code, but its not working...

window.setInterval(function () {
  var week1 = document.getElementsByName("week1").value;
  var week2 = document.getElementsByName("week2").value;
  var week3 = document.getElementsByName("week3").value;
  var week4 = document.getElementsByName("week4").value;
  var week5 = document.getElementsByName("week5").value;

  var weekTotal = week1 + week2 + week3 + week4 + week5;

  document.getElementById("totalHours").innerHTML = weekTotal;
}, 1000);

Any ideas?

2
  • @LeeTaylor there are two obvious bugs. Misuse of getElementsByName, and getting string concatenation instead of addition. Commented Dec 20, 2012 at 22:38
  • @Alnitak - I see that. I was using the review system, so didn't see the answers... Commented Dec 20, 2012 at 22:42

3 Answers 3

2
  1. use element IDs, not names - then you can use document.getElementById()

  2. cache those element variables so you don't have to call document.getElementById() every time

  3. convert .value into a number with parseInt(s, 10) - although you haven't said how it fails this will be causing you a problem because .value is normally a string and using + on strings does concatenation, not addition.

  4. don't do it in a timer loop - it'll prevent updates from happening in real time. Instead, use an onchange (and/or oninput) event handler which will be called immediately whenever any value is updated. With onchange the sum would be calculated each time the user moves from one input to another, with oninput it'll recalculate on each key press (or copy/paste, etc).

See http://jsfiddle.net/alnitak/7Gzs6/

var form = document.getElementById('myform');
var inputs = form.getElementsByTagName('input');
var totalView = document.getElementById('total');

function add(ev) {
    var total = 0;
    for (var i = 0, n = inputs.length; i < n; ++i) {
        var v = parseInt(inputs[i].value, 10);
        if (!isNaN(v)) {
            total += v;
        }
    }
    totalView.innerHTML = total;
}

form.addEventListener('change', add, false);​
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you so much. This should help me finish the rest.
There is no need to use getElementById at all. The OP can use var form = document.forms.myform, and then form.week1.value and so on. Form controls must have names to be successful. If they have names, they don't need IDs. Also, not all browsers support the change event for forms. The listener should be on each input that might change.
Would you recommend caching the elements because getElementByID is an expensive operation, or for stylistic reasons?
@JimmyBreck-McKye mostly because IMHO one should never repeatedly call a function just to obtain the same result over and over.
@JimmyBreck-McKye—getElementById isn't particularly expensive, it's just not necessary. It also means the controls must have a name and ID when they can be referenced just as easily by name and therefore don't need an ID.
|
0

document.getElementsByName returns an array

So you probably want to retrieve the first element [0] with name 'week1' and so on.

var week1 = document.getElementsByName("week1")[0].value;

Comments

0

As an alternative to the answer you've selected, consider making use of the collections available and use property access rather than function calls. e.g.

<script>

// Test that v is an integer
function isInt(v) {
  return /^\d+$/.test(v + '');
}

// Update the total if entered value is an integer
function updateTotal(e) {
  var e = e || window.event;
  var el = e.target || e.srcElement;
  var value = el.value;

  // If value is an integer, use it
  if (isInt(value)) {
    el.form.total.value = +el.form.total.value + +value;

  // Otherwise, do nothing (or show an error message asking
  // the user to input a valid value)
  } else {
    e.preventDefault();
  }
  return false;
}

// Add listeners to elements that need them
window.onload = function() {
  var form = document.forms['f0'];
  var els = form.elements;
  var re = /^week/;
  var total = 0;

  for (var i=0, iLen=els.length; i<iLen; i++) {
    if (re.test(els[i].name)) {
      els[i].onchange = updateTotal;
    }
  }
}
</script>

<form id="f0" action="">
  week1<input name="week1" value="0"><br>
  week2<input name="week2" value="0"><br>
  week3<input name="week3" value="0"><br>
  week4<input name="week4" value="0"><br>
  week5<input name="week5" value="0"><br>
  total<input name="total" value="0" readonly>
  <input type="reset"><input type="submit">
</form>

The isInt function is a bit simple, it should trim leading and trailing spaces etc. but is sufficient to show that you must test the input before using it in an operation. This is also a great example of where inline listeners are probably a better solution.

2 Comments

by property access are you talking about .onchange? That's very old school... In any event (no pun intended) I don't think your answer is correct - it always adds to the total, but never amends the total if a value is changed.
Regarding property access: I mean direct access to form controls. Regarding the total: yes, you're correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.