JavaScript:获取已编辑/更新的输入数

Mor*_*ori 24 html javascript forms input

情境

我的学生每学期至少需要学习一门科学,一门物理和一门历史考试。以下表格给出了正确的平均成绩以及学生的最终成绩:

document.getElementById('calcBtn').addEventListener('click', function() {
  var scienceTest1 = document.getElementById('scienceTest1').value;
  var scienceTest2 = document.getElementById('scienceTest2').value;
  var scienceTest3 = document.getElementById('scienceTest3').value;
  var physicsTest1 = document.getElementById('physicsTest1').value;
  var physicsTest2 = document.getElementById('physicsTest2').value;
  var physicsTest3 = document.getElementById('physicsTest3').value;
  var historyTest1 = document.getElementById('historyTest1').value;
  var historyTest2 = document.getElementById('historyTest2').value;
  var historyTest3 = document.getElementById('historyTest3').value;
  var scienceAverage = document.getElementById('scienceAverage');
  var physicsAverage = document.getElementById('physicsAverage');
  var historyAverage = document.getElementById('historyAverage');
  var finalGrade = document.getElementById('finalGrade');
  scienceAverage.value = (Number(scienceTest1) + Number(scienceTest2) + Number(scienceTest3)) / 3;
  physicsAverage.value = (Number(physicsTest1) + Number(physicsTest2) + Number(physicsTest3)) / 3;
  historyAverage.value = (Number(historyTest1) + Number(historyTest2) + Number(historyTest3)) / 3;
  finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
Run Code Online (Sandbox Code Playgroud)
<form>
  Science: <input type="number" id="scienceTest1">
  <input type="number" id="scienceTest2">
  <input type="number" id="scienceTest3">
  <output id="scienceAverage"></output>
  <br> Physics: <input type="number" id="physicsTest1">
  <input type="number" id="physicsTest2">
  <input type="number" id="physicsTest3">
  <output id="physicsAverage"></output>
  <br> History: <input type="number" id="historyTest1">
  <input type="number" id="historyTest2">
  <input type="number" id="historyTest3">
  <output id="historyAverage"></output>
  <br>
  <input type="button" value="Calculate" id="calcBtn">
  <output id="finalGrade"></output>
</form>
Run Code Online (Sandbox Code Playgroud)

问题是,只有在所有字段都被编辑的情况下,它才有效。如果学生不参加某些考试,平均成绩将不会显示正确的值。我知道这是因为3在计算平均成绩时会除以固定数字:

scienceAverage.value = (Number(scienceTest1) + Number(scienceTest2) + Number(scienceTest3)) / 3;
physicsAverage.value = (Number(physicsTest1) + Number(physicsTest2) + Number(physicsTest3)) / 3;
historyAverage.value = (Number(historyTest1) + Number(historyTest2) + Number(historyTest3)) / 3;
Run Code Online (Sandbox Code Playgroud)

有一种简单的方法来获取下一行中已更改的输入字段的数量?我将尝试了解您的方法,然后将我的表单开发为多行。

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;
});
Run Code Online (Sandbox Code Playgroud)
<form>
  <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>
Run Code Online (Sandbox Code Playgroud)

Dac*_*nny 17

看起来您需要检查输入的值是否为有效数字,然后才能将其用于计算每门课程平均值的算法中。一种方法是通过以下检查:

if (!Number.isNaN(Number.parseFloat(input.value))) {
  /* Use input.value in average calculation */
}
Run Code Online (Sandbox Code Playgroud)

您还可以考虑如下所示调整脚本和HTML,这将使您能够概括并重新使用这三个类中每一个的平均计算,如下所示:

if (!Number.isNaN(Number.parseFloat(input.value))) {
  /* Use input.value in average calculation */
}
Run Code Online (Sandbox Code Playgroud)
document.getElementById('calcBtn').addEventListener('click', function() {

  /* Generalise the calculation of updates for specified course type */
  const calculateForCourse = (cls) => {

    let total = 0
    let count = 0

    /* Select inputs with supplied cls selector and iterate each element */
    for (const input of document.querySelectorAll(`input.${cls}`)) {

      if (!Number.isNaN(Number.parseFloat(input.value))) {
      
        /* If input value is non-empty, increment total and count for
        subsequent average calculation */
        total += Number.parseFloat(input.value);
        count += 1;
      }
    }

    /* Cacluate average and return result */
    return { count, average : count > 0 ? (total / count) : 0 }
  }

  /* Calculate averages using shared function for each class type */
  const calcsScience = calculateForCourse('science')
  const calcsPhysics = calculateForCourse('physics')
  const calcsHistory = calculateForCourse('history')
  
  /* Update course averages */
  document.querySelector('output.science').value = calcsScience.average
  document.querySelector('output.physics').value = calcsPhysics.average
  document.querySelector('output.history').value = calcsHistory.average
  
  /* Update course counts */
  document.querySelector('span.science').innerText = `changed:${calcsScience.count}`
  document.querySelector('span.physics').innerText = `changed:${calcsPhysics.count}`
  document.querySelector('span.history').innerText = `changed:${calcsHistory.count}`

  /* Update final grade */
  var finalGrade = document.getElementById('finalGrade');

  finalGrade.value = (calcsScience.average * 5 + calcsPhysics.average * 3 + calcsHistory.average * 2) / 10;
});
Run Code Online (Sandbox Code Playgroud)

更新资料

要扩展第一个答案,请参阅以下代码段中的文档以回应您的问题更新:

<!-- Add class to each of the course types to allow script to distinguish
     between related input and output fields -->
<form>
  Science:
  <input type="number" class="science" id="scienceTest1">
  <input type="number" class="science" id="scienceTest2">
  <input type="number" class="science" id="scienceTest3">
  <output id="scienceAverage" class="science"></output>
  <span class="science"></span>
  <br> Physics:
  <input type="number" class="physics" id="physicsTest1">
  <input type="number" class="physics" id="physicsTest2">
  <input type="number" class="physics" id="physicsTest3">
  <output id="physicsAverage" class="physics"></output>
  <span class="physics"></span>
  <br> History:
  <input type="number" class="history" id="historyTest1">
  <input type="number" class="history" id="historyTest2">
  <input type="number" class="history" id="historyTest3">
  <output id="historyAverage" class="history"></output>
  <span class="history"></span>
  <br>
  <input type="button" value="Calculate" id="calcBtn">
  <output id="finalGrade"></output>
</form>
Run Code Online (Sandbox Code Playgroud)
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');
  
  /* This variable counts the number of inputs that have changed */
  var changesDetected = 0;
  
  /* If value of test1 field "not equals" the empty string, then 
  we consider this a "changed" field, so we'll increment our 
  counter variable accordinly */
  if(test1 != '') {
    changesDetected = changesDetected + 1;
  }
  /* Apply the same increment as above for test2 field */
  if(test2 != '') {
    changesDetected = changesDetected + 1;
  }
  /* Apply the same increment as above for test3 field */
  if(test3 != '') {
    changesDetected = changesDetected + 1;
  }
  
  /* Calculate average from changesDetected counter.
  We need to account for the case where no changes
  have been detected to prevent a "divide by zero" */
  if(changesDetected != 0) {
    average.value = (Number(test1) + Number(test2) + Number(test3)) / changesDetected;
  }
  else {
    average.value = 'Cannot calculate average'
  }
  
  /* Show a dialog to box to display the number of fields changed */
  alert("Detected that " + changesDetected + " inputs have been changed")
});
Run Code Online (Sandbox Code Playgroud)

更新2

可以使用如下循环简化先前的更新:

<form>
  <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>
Run Code Online (Sandbox Code Playgroud)
document.getElementById('calcBtn').addEventListener('click', function() {
  
  let changesDetected = 0;
  let total = 0;
  const ids = ['test1', 'test2', 'test3'];
  
  for(const id of ids) {
    const value = document.getElementById(id).value;
    if(value != '') {
      changesDetected += 1;
      total += Number(value);
    }
  }
  
  var average = document.getElementById('average');
  
  if(changesDetected != 0) {
    average.value = total / changesDetected;
  }
  else {
    average.value = 'Cannot calculate average'
  }
    
  alert("Detected that " + changesDetected + " inputs have been changed")
});
Run Code Online (Sandbox Code Playgroud)

更新3

另一种基于您的JSFiddle的简洁方法如下:

<form>
  <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>
Run Code Online (Sandbox Code Playgroud)
document.getElementById('calculator').addEventListener('click', function() {
  var physicsAverage = document.getElementById('physicsAverage'),
    historyAverage = document.getElementById('historyAverage');

  physicsAverage.value = calculateAverageById('physics')
  historyAverage.value = calculateAverageById('history');
});

function calculateAverageById(id) {
  /* Get all input descendants of element with id */
  const inputs = document.querySelectorAll(`#${id} input`);

  /* Get all valid grade values from selected input elements */
  const grades = Array.from(inputs)
    .map(input => Number.parseFloat(input.value))
    .filter(value => !Number.isNaN(value));

  /* Return average of all grades, or fallback message if no valid grades present */
  return grades.length ? (grades.reduce((sum, grade) => (sum + grade), 0) / grades.length) : 'No assessment made!'
}
Run Code Online (Sandbox Code Playgroud)

这里的主要区别是:

  • document.querySelectorAll(#$ {id}输入);与模板文字一起使用以提取input元素的元素id
  • 使用的Array.from(inputs),用于将所述查询的结果,以一个阵列的多个可读装置
  • 在将元素转换和过滤为有效数值以进行后续平均值计算时使用Number.parseFloat和的使用Number.isNaNinput

希望有帮助!


Jor*_*uro 7

一个很好的开始是将您的ID更改为Class,以将您的输入放入逻辑组。下一步是从值不为null的特定组中获取输入。为此,我们可以选择例如.scienceTest然后过滤掉空字符串项目。

我添加了一个辅助函数,values以从节点列表中提取值并将其放入普通数组中。

我们可以使用a Boolean来测试空字符串。我们还使用将所有字符串转换为数字Number。这是在onlyNumbers函数中完成的。

接下来,我们需要计算每组的平均值。这很容易,因为我们有一个过滤的数字列表。我们要做的就是计算总和并除以数组长度。这是通过我们的小avrg功能完成的。

 

document.getElementById('calcBtn').addEventListener('click', function() {
  var scienceTest = getGrades('.scienceTest')
  var physicsTest = getGrades('.physicsTest')
  var historyTest = getGrades('.historyTest')
  
  var scienceAverage = document.getElementById('scienceAverage');
  var physicsAverage = document.getElementById('physicsAverage');
  var historyAverage = document.getElementById('historyAverage');
  
  var finalGrade = document.getElementById('finalGrade');
  
  scienceAverage.value = avrg(scienceTest)
  physicsAverage.value = avrg(physicsTest)
  historyAverage.value = avrg(historyTest)
  
  finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
  
});

function avrg(list) {
	return list.length ? list.reduce((acc, i) => acc + i, 0) / list.length : 0
}

function getGrades(selector) {
	return onlyNumbers(values(document.querySelectorAll(selector)))
}
function onlyNumbers(list) {
		return list.filter(Boolean).map(Number)
}

function values(nodelist) {
		return Array.prototype.map.call(nodelist, (node) => node.value)
}
Run Code Online (Sandbox Code Playgroud)
<form>
  Science: <input type="number" class="scienceTest">
  <input type="number" class="scienceTest">
  <input type="number" class="scienceTest">
  <output id="scienceAverage"></output>
  <br> Physics: <input type="number" class="physicsTest">
  <input type="number" class="physicsTest">
  <input type="number" class="physicsTest">
  <output id="physicsAverage"></output>
  <br> History: <input type="number" class="historyTest">
  <input type="number" class="historyTest">
  <input type="number" class="historyTest">
  <output id="historyAverage"></output>
  <br>
  <input type="button" value="Calculate" id="calcBtn">
  <output id="finalGrade"></output>
</form>
Run Code Online (Sandbox Code Playgroud)

更新:简化示例

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');
  // Put all field values in array, Filter empty values out, cast values to Number
  var rowValues = [test1, test2, test3].filter(Boolean).map(Number)

  console.log('Number of changed fields', rowValues.length)

  // calculate average by reducing the array to the sum of its remaining values then divide by array length
  average.value = rowValues.reduce((sum, grade) => sum + grade, 0) / rowValues.length;
});
Run Code Online (Sandbox Code Playgroud)
<form>
  <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>
Run Code Online (Sandbox Code Playgroud)

更新额外内容:基于OP的jsfiddle示例中的注释

document.getElementById('calculator').addEventListener('click', function() {
  var physicsAverage = document.getElementById('physicsAverage'),
    historyAverage = document.getElementById('historyAverage');

  physicsAverage.value = calculateAverageById('physics')
  historyAverage.value = calculateAverageById('history');
});

function calculateAverageById(id) {
	// Get all inputs under Id
  var inputs = document.getElementById(id).getElementsByTagName('input')

  var values =
    Array.prototype.slice.call(inputs) // From HTMLCollection to Array
    .map(e => e.value.trim()) // Return all .value from input elements
    .filter(Boolean) // Filter out any empty strings ""
    .map(Number) // convert remaining values to Numbers
  return (values.length) ? // if length is greater then 0
    values.reduce((sum, grade) => sum + grade, 0) / values.length // Return average
    :
    'No assessment made!' // else return this message
}
Run Code Online (Sandbox Code Playgroud)
    <form>
  <p id="physics">
    Physics:
    <input type="number">
    <input type="number">
    <input type="number">
    <output id="physicsAverage"></output>
  </p>
  <p id="history">
    History:
    <input type="number">
    <input type="number">
    <input type="number">
    <output id="historyAverage"></output>
  </p>
  <button type="button" id="calculator">Calculate</button>
</form>
Run Code Online (Sandbox Code Playgroud)


Vis*_*s R 5

您不必一直将其除以3,而是可以根据学生连续更新的输入字段数来动态计算此数字。

这是工作代码:

function getValueAndTotal(element){
  var valueChanged = (element.defaultValue === element.value || element.value === "") ? 0 : 1;  
  return { value: Number(element.value), total: valueChanged };
}

document.getElementById('calcBtn').addEventListener('click', function() {
  var scienceTest1 = getValueAndTotal(document.getElementById('scienceTest1'));
  var scienceTest2 = getValueAndTotal(document.getElementById('scienceTest2'));
  var scienceTest3 = getValueAndTotal(document.getElementById('scienceTest3'));

  var physicsTest1 = getValueAndTotal(document.getElementById('physicsTest1'));
  var physicsTest2 = getValueAndTotal(document.getElementById('physicsTest2'));
  var physicsTest3 = getValueAndTotal(document.getElementById('physicsTest3'));

  var historyTest1 = getValueAndTotal(document.getElementById('historyTest1'));
  var historyTest2 = getValueAndTotal(document.getElementById('historyTest2'));
  var historyTest3 = getValueAndTotal(document.getElementById('historyTest3'));

  var scienceAverage = document.getElementById('scienceAverage');
  var physicsAverage = document.getElementById('physicsAverage');
  var historyAverage = document.getElementById('historyAverage');

  var finalGrade = document.getElementById('finalGrade');
  var scienceTotalTests = scienceTest1.total + scienceTest2.total + scienceTest3.total;
  var physicsTotalTests = physicsTest1.total + physicsTest2.total + physicsTest3.total;
  var historyTotalTests = historyTest1.total + historyTest2.total + historyTest3.total;

  scienceAverage.value = (scienceTotalTests === 0 ? 0 : (scienceTest1.value + scienceTest2.value + scienceTest3.value) / scienceTotalTests);
  physicsAverage.value = (physicsTotalTests === 0 ? 0 : (physicsTest1.value + physicsTest3.value + physicsTest3.value) / physicsTotalTests);
  historyAverage.value = (historyTotalTests === 0 ? 0 : (historyTest1.value + historyTest2.value + historyTest3.value) / historyTotalTests);

  finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
Run Code Online (Sandbox Code Playgroud)
<form>
  Science: 
    <input type="number" id="scienceTest1" class="scienceTest">
    <input type="number" id="scienceTest2" class="scienceTest">
    <input type="number" id="scienceTest3" class="scienceTest">
    <output id="scienceAverage"></output>
  <br>Physics: 
    <input type="number" id="physicsTest1">
    <input type="number" id="physicsTest2">
    <input type="number" id="physicsTest3">
    <output id="physicsAverage"></output>
  <br>History: 
    <input type="number" id="historyTest1">
    <input type="number" id="historyTest2">
    <input type="number" id="historyTest3">
    <output id="historyAverage"></output>
  <br>
    <input type="button" value="Calculate" id="calcBtn">
    <output id="finalGrade"></output>
</form>
Run Code Online (Sandbox Code Playgroud)


jos*_*las 5

这有点丑陋,但您可以将测试成绩视为布尔值:如果有任何测试成绩的价值为1,否则为0。

由于input.value类型为string,因此false当输入为空("")或true其中有任何数字时,将其转换为布尔值。

使用OP的较小代码段:

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 testCount = Boolean(test1) + Boolean(test2) + Boolean(test3);
  // alternatively: var testCount = !!test1 + !!test2 + !!test3

  var average = document.getElementById('average');
  average.value = (Number(test1) + Number(test2) + Number(test3)) / testCount;
});
Run Code Online (Sandbox Code Playgroud)
<form>
  <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>
Run Code Online (Sandbox Code Playgroud)