Welcome to WebmasterWorld Guest from 34.229.24.100

Forum Moderators: open

# Get the number of edited inputs

#### Rain_Lover

1:25 pm on Mar 5, 2019 (gmt 0)

#### Full Member

joined:Mar 1, 2010
posts: 209

Scenario

Every semester my students need to take at least one test. The following form gives the right average grade of a student:
``<!DOCTYPE html><html lang="en"> <head> <title>Average Grade</title> </head> <body> <form>Math: <input type="number" id="test1"> <input type="number" id="test2"> <input type="number" id="test3"> <output id="average"></output> <br> <input type="button" value="Calculate" id="calcBtn"> </form> <script> document.getElementById('calcBtn').addEventListener('click', function() {  var test1 = document.getElementById('test1').value;  var test2 = document.getElementById('test2').value;  var test3 = document.getElementById('test3').value;  var average = document.getElementById('average');  average.value = (Number(test1)+Number(test2)+Number(test3)) / 3; }); </script> </body></html>``

DEMO [jsfiddle.net]

The problem is it works right only if all the fields are edited. If the student doesn't take some tests, the average grade won't show the right value. I know it's because of dividing by the fixed number 3 when it calculates the average grade:
``average.value = (Number(test1)+Number(test2)+Number(test3)) / 3;``

Question

What is a simple approach to get the number of changed input fields?

#### topr8

1:58 pm on Mar 5, 2019 (gmt 0)

#### Senior Member

joined:Apr 19, 2002
posts:3478

couldn't you make the number 3 a variable (divideby) instead with an initial value of zero.

then ...
if test1 > 0 ... add 1 to the value of divideby
if test2 > 0 ... add 1 to the value of divideby
if test3 > 0 ... add 1 to the value of divideby

#### Rain_Lover

2:03 pm on Mar 5, 2019 (gmt 0)

#### Full Member

joined:Mar 1, 2010
posts: 209

Good idea, but I don't know how to do it.

#### topr8

8:46 pm on Mar 5, 2019 (gmt 0)

#### Senior Member

joined:Apr 19, 2002
posts:3478

i don't really use js ... something like this ... although i imagine there is a more elegant way of doing it.
``document.getElementById('calcBtn').addEventListener('click', function() { var divideby = 0; var test1 = document.getElementById('test1').value; var test2 = document.getElementById('test2').value; var test3 = document.getElementById('test3').value; if(test1>0){divideby++;} if(test2 > 0){divideby++;} if(test3 > 0){divideby++;} var average = document.getElementById('average'); average.value = (Number(test1) + Number(test2) + Number(test3)) / divideby;});``

#### NickMNS

9:54 pm on Mar 5, 2019 (gmt 0)

#### Senior Member

joined:Apr 1, 2016
posts:2619

Here is the fiddle updated:
[jsfiddle.net...]

Here is the code:
``document.querySelector('#calcBtn').addEventListener('click', function() {const inputArr = Array.from(document.querySelectorAll('input[type=number]')), average = document.querySelector('output'); let validScores = [];inputArr.forEach(function(score){ if(parseInt(score.value) > 0) validScores.push(parseInt(score.value)) }); const count = validScores.length, scoreSum = validScores.reduce((partial_sum, a) => partial_sum + a); average.value = scoreSum / count});``

Explanation:
Get each of the inputs as an array. querySelectorAll gets all the inputs but as a node list. Array.from converts the node list to an array. Then I create an empty array to store the valid scores. Using, forEach I loop through the array of inputs and pass their values through a conditional if, in this case > 0 (my need to be something else). If the value meets the condition it is added to the array of valid scores. Then I take the valid scores, count them, sum them and finally divide the sum by the count.

With this approach you can have has as many inputs as needed and still use the same code.

Note: this script uses ECMAScript6 and may not work on older browsers.

I hope this helps.

#### Rain_Lover

3:52 am on Mar 6, 2019 (gmt 0)

#### Full Member

joined:Mar 1, 2010
posts: 209

@NickMNS: Thanks for the answer, but I'd rather use the older version of JavaScript.

#### lucy24

6:36 am on Mar 6, 2019 (gmt 0)

#### Senior Member from US

joined:Apr 9, 2011
posts:15699

if(test2 > 0)
What happens if they took the test but scored 0 on it?

In any case this seems like a good place to use name instead of id. You can then have a group of fields with the same name, no need to decide ahead of time how many there are, and loop through all of them, adding 1 to the value of "divideby" each time. The command is
blahblah = document.getElementsByName("tests")
(note that it becomes Elements, plural, not Element)
and then a loop such as
for (count = 0; count < blahblah.length; count++)

#### topr8

1:02 pm on Mar 6, 2019 (gmt 0)

#### Senior Member

joined:Apr 19, 2002
posts:3478

>>What happens if they took the test but scored 0 on it?

yes indeed, i was just looking at a very quick simple way to do it - and i don't use js, but no-one else had answered the question.

i guess one could test to see if the field was empty rather than zero.

anyway nick sorted it out properly.

#### NickMNS

2:47 pm on Mar 6, 2019 (gmt 0)

#### Senior Member

joined:Apr 1, 2016
posts:2619

What happens if they took the test but scored 0 on it?

That is why I wrote in my explanation:
(may need to be something else).

There are many conditional checks that could be done, such as checking for length, for null, for empty string etc... >0 was the easiest but not best. @Rain_Lover can select the one that is meets the needs.

As for ECMAScript6 there are really only 2 things that need to change Array.from, and the reduce. Both can be rewritten using a for loop as described by Lucy24
``for (i = 0; i < validScores.length; i++)``

#### Rain_Lover

5:12 pm on Mar 6, 2019 (gmt 0)

#### Full Member

joined:Mar 1, 2010
posts: 209

Here's an attempt: [jsfiddle.net...]
I wonder if you see any problems or any way to improve it.

#### Rain_Lover

4:47 pm on Mar 9, 2019 (gmt 0)

#### Full Member

joined:Mar 1, 2010
posts: 209

Here's the final update: [jsfiddle.net...]

#### NickMNS

4:58 pm on Mar 9, 2019 (gmt 0)

#### Senior Member

joined:Apr 1, 2016
posts:2619

Looks good!

#### Rain_Lover

5:20 pm on Mar 9, 2019 (gmt 0)

#### Full Member

joined:Mar 1, 2010
posts: 209

Thanks for reviewing!