JavaScript: получить количество отредактированных / обновленных входных данных - PullRequest
0 голосов
/ 04 марта 2019

Сценарий

Каждый семестр моим студентам необходимо сдать хотя бы один тест по естествознанию, один экзамен по физике и один экзамен по истории.Следующая форма дает правильные средние оценки, а также итоговую оценку ученика:

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;
});
<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>

Проблема в том, что это работает, только если все поля редактируются.Если учащийся не сдает тесты, средние оценки не будут отображать правильные значения.Я знаю, что это из-за деления на фиксированное число 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;

Вопрос

Какой простой способ получить изменение числа поля ввода в следующей строке?Я попытаюсь понять ваш метод, а затем разрабатываю форму в несколько строк.

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;
});
<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>

Ответы [ 14 ]

0 голосов
/ 02 апреля 2019

Какой простой способ получить количество измененных полей ввода

Мы можем присвоить каждому input пользовательский атрибут data, равный значению input, а затемисключить пустые при подсчете их.Следующий универсальный скрипт может использоваться для любого количества курсов:

var form = document.querySelector('form');

function calculateAverage(fieldset) {
  var total = 0;
  var inputs = fieldset.querySelectorAll('input');
  for (var input of inputs) {
    total += Number(input.value);
    input.dataset.value = input.value;
  }
  return total / fieldset.querySelectorAll('input:not([data-value=""])').length;
}

function displayAverages() {
  var fieldsets = form.querySelectorAll('fieldset');
  for (var fieldset of fieldsets) {
    var avg = calculateAverage(fieldset);
    var output = fieldset.querySelector('output');
    if (isNaN(avg)) {
      output.value = 'Please enter a grade.';
    } else {
      output.value = 'Average: ' + avg.toFixed(1);
    }
  }
}

form.querySelector('button').addEventListener('click', displayAverages);
body {
  display: flex;
}

fieldset {
  margin: 0 0 16px;
}

input {
  width: 4em;
}

output {
  display: block;
  height: 1em;
  margin: 8px 0 0 2px;
}
<form>
  <fieldset>
    <legend>Physics</legend>
    <input type="number">
    <input type="number">
    <input type="number">
    <output></output>
  </fieldset>
  <fieldset>
    <legend>History</legend>
    <input type="number">
    <input type="number">
    <input type="number">
    <output></output>
  </fieldset>
  <button type="button">Calculate</button>
</form>
0 голосов
/ 11 марта 2019

document.getElementById('calcBtn').addEventListener('click', function() {
var testcount = [];
var count = 0;
testcount = Array.prototype.slice.call(document.getElementsByClassName('test1'))
for(var i=0;i<testcount.length;i++)
{
 if(Number(testcount[i].value) > 0)
 {
  count=count+1;
  }
 
}
  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)) / count;
});
<form>
  <input type="number" class="test1" id="test1">
  <input type="number" class="test1" id="test2">
  <input type="number" class="test1" id="test3">
  <output id="average"></output>
  <br>
  <input type="button" value="Calculate" id="calcBtn">
</form>

в вышеприведенном выводе достигается путем добавления атрибута класса во входной тег (присваивайте то же имя для той же группы элементов управления).Во-вторых, это циклический просмотр этого объекта класса для получения количества непустых или ненулевых значений.

0 голосов
/ 12 марта 2019

Я рекомендую избегать нескольких полей ввода для чтения в нескольких входах.В моем случае я использую точки с запятой для разделения отдельных значений внутри поля ввода.Таким образом, я могу ввести столько значений, сколько захочу (хотя бы одно значение).Поэтому моя форма выглядит следующим образом:

<!-- form.html -->
<form>
  Science: <input type="text" id="scienceTest">
  <output id="scienceAverage"></output>
  <br> Physics: <input type="text" id="physicsTest">
  <output id="physicsAverage"></output>
  <br> History: <input type="text" id="historyTest">
  <output id="historyAverage"></output>
  <br>
  <input type="button" value="Calculate" id="calcBtn">
  <output id="finalGrade"></output>
</form>
<script src="script.js"></script>

А мой JavaScript выглядит так:

// script.js
(function() {
  var scienceTest = document.getElementById('scienceTest');
  var physicsTest = document.getElementById('physicsTest');
  var historyTest = document.getElementById('historyTest');
  var scienceAverage = document.getElementById('scienceAverage');
  var physicsAverage = document.getElementById('physicsAverage');
  var historyAverage = document.getElementById('historyAverage');
  var finalGrade = document.getElementById('finalGrade');

  function sumArray(sum, item) {
    return sum + item;
  }

  document.getElementById('calcBtn').addEventListener('click', function() {
    // fetch the string of the input and split into its separate numbers
    var scienceGradeStrings = scienceTest.value.split(";");
    var physicsGradeStrings = physicsTest.value.split(";");
    var historyGradeStrings = historyTest.value.split(";");

    // calculate the averages
    scienceAverage.value = scienceGradeStrings
      // convert the grades from strings to numbers
      .map(Number)
      // sum all grades together
      .reduce(sumArray, 0)
      // calculate the average grade
      / scienceGradeStrings.length;
    physicsAverage.value = physicsGradeStrings.map(Number).reduce(sumArray, 0) / physicsGradeStrings.length;
    historyAverage.value = historyGradeStrings.map(Number).reduce(sumArray, 0) / historyGradeStrings.length;
    finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
  });
})();
0 голосов
/ 08 марта 2019

Это немного некрасиво, но вы можете рассматривать результаты тестов как логические: если есть какой-либо результат теста, который стоит 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;
});
<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>
0 голосов
/ 11 марта 2019

Введите счетчик для функции.После каждого нажимайте , проверяйте, являются ли входные значения '' или нет, поскольку это будет строка перед приведением.Если это ничего не делать, то операция троичный вернет false

 test1!=''?num++:false;

Если test1=='', то false else incrementсчетчик .Перед вычислением среднего значения проверьте, равен ли счетчик 0, установлен ли он на единицу.Если оно равно нулю, результатом деления на ноль будет бесконечность, и мы получим NaN в качестве выхода, а счетчик, установленный в 1, даст 0.

document.getElementById('calcBtn').addEventListener('click', function() {
let num=0;
  var test1 = document.getElementById('test1').value;
  test1!=''?num++:false;
  var test2 = document.getElementById('test2').value;
  test2!=''?num++:false;
  var test3 = document.getElementById('test3').value;
  test3!=''?num++:false;
  var average = document.getElementById('average');
  num==0?num++:false;
  average.value = (Number(test1) + Number(test2) + Number(test3)) / num;
});
<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>
0 голосов
/ 07 марта 2019

Вы можете создать объект с именем tests = {} и сохранить свои тесты в виде массива внутри него, чтобы привести пример. Я написал некоторый код только для одной темы ниже, которую вы можете изменить позже.

Кроме того, я использовал классы вместо идентификаторов , чтобы уменьшить сложность кода и повторяемость.

Обновление : обновлен код ниже, чтобы он был более динамичным и гибким для нескольких предметов.

document.getElementById('calcBtn').addEventListener('click', function() {

  // create a tests object and have subject specific test inside it
  var tests = {
    "Science": [],
    "Physics": [],
    "History": []
  };

  //looping over all subjects 
  for (var key in tests) {

    // this can be looped as well if you have multiple subjects
    var test = document.getElementsByClassName(key);
    for (i = 0; i < test.length; i++) {
      if (test[i].value != null || test[i].value != "") {
        tests[key].push(Number(test[i].value));
      }
    }

    // populate average by using reduce function 
    document.getElementById(key).value = tests[key].reduce((prev, curr) => prev + curr) / tests[key].length;
  }
});
<form>
  <fieldset>
    <legend>Science</legend>
    <input type="number" class="Science">
    <input type="number" class="Science">
    <input type="number" class="Science">
    <output id="Science"></output>
  </fieldset>

  <fieldset>
    <legend>Physics</legend>
    <input type="number" class="Physics">
    <input type="number" class="Physics">
    <input type="number" class="Physics">
    <output id="Physics"></output>
  </fieldset>

  <fieldset>
    <legend>History</legend>
    <input type="number" class="History">
    <input type="number" class="History">
    <input type="number" class="History">
    <output id="History"></output>
  </fieldset>
  <br>
  <input type="button" value="Calculate" id="calcBtn">
</form>
0 голосов
/ 08 марта 2019

Метод

Проблема с делением на фиксированное число 3 может быть решена с помощью свойства Длина массива и делает это значение динамическим.

Шаг 1 : Поместите все объекты в массивы и отфильтруйте, если входные значения имеют значения.

Шаг 2 : Получите среднее значение по предметам.

Шаг 3 : Рассчитать итоговую оценку с весами.

Есть две функции, которые используются несколько раз.isTruthy и average.

Чтобы уменьшить среднюю функцию, я разбил ее на sum и average

document.getElementById('calcBtn').addEventListener('click', function() {

  // Helper Functions

  function isTruthy (score) {
    return !!score
  }
  
  function sum (scores) {
    var total = 0;
    for (var counter=0; counter<scores.length; counter++) {
      total += (Number(scores[counter]) || 0);
    }
    return total
  }
  
  function average (scores) {
    return (sum(scores) / scores.length) || 0
  }
  
  // Step 1
  var scienceScores = [
    document.getElementById('scienceTest1').value,
    document.getElementById('scienceTest2').value,
    document.getElementById('scienceTest3').value
  ].filter(isTruthy)
  
  var physicsScores = [
    document.getElementById('physicsTest1').value,
    document.getElementById('physicsTest2').value,
    document.getElementById('physicsTest3').value
  ].filter(isTruthy)
  
  var historyScores = [
    document.getElementById('historyTest1').value,
    document.getElementById('historyTest2').value,
    document.getElementById('historyTest3').value
  ].filter(isTruthy)
  
  var scienceAverage = document.getElementById('scienceAverage');
  var physicsAverage = document.getElementById('physicsAverage');
  var historyAverage = document.getElementById('historyAverage');
  
  var finalGrade = document.getElementById('finalGrade');
  
  // Step 2
  scienceAverage.value = average(scienceScores);
  physicsAverage.value = average(physicsScores);
  historyAverage.value = average(historyScores);
  
  // Step 3
  finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
<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>
0 голосов
/ 07 марта 2019

Вы делите значение на 3, поэтому оно дает меньший результат, чем ожидалось.

  • Делайте html-код вашего кода динамически.
  • Не делайтеиспользуйте слишком много переменных (scienceTest1,scienceTest2.....), вместо этого используйте циклы, которые хранят значения в array
  • Запись в таком виде Number(scienceTest1) + Number(scienceTest2) + Number(scienceTest3)) / 3 плохая, потому что вы можете иметь больше тестов и больше шансов на ошибку типа.Вместо этого сохраните значения в массиве и в конце используйте Array.prototype.reduce(), чтобы добавить их.
  • Для массива значений вам нужно проверить, если value !=='', перед тем как вставить его в массив, чтобы онполучит правильное среднее значение.

Код является полностью динамическим, вы можете иметь любые предметы и любые нет тестов

//This is list of subjects. You can change it will work same
let subjects = ['science','physics','history'];
let noOfTests = 3;
//add <form> element to body
document.body.innerHTML = '<form></form>'
//getting that form as an element.
let form = document.querySelector('form')

//Creating the HTML dymamically

subjects.forEach(sub =>{
   //setting the title of the subject
   form.innerHTML += sub + ':' + '<br>'; 
   for(let i = 0;i<noOfTests;i++){
     //generating input feilds equal of 'noOfTests' for each subject
     form.innerHTML += `<input type="number" id="${sub}Test${i+1}" /><br>`
   }
   //adding the output element to after addign all inputs.
   form.innerHTML += `<output id="${sub}Average"></output><br>` 
})
//Adding calculate button and finalOuput element.
form.innerHTML += `<br><input type="button" value="Calculate" id="calcBtn">
  <output id="finalGrade"></output>`



document.getElementById('calcBtn').addEventListener('click', function() {
  //'total' is array which will contain average of each subject
  let total = [];
  //looping thorugh each subject in 'subjects' array.
  subjects.forEach(sub => {
    //'vals' will store the values currect subject we are looping
    let vals = []
    
    for(let i = 0;i<noOfTests;i++){
      //getting the value of each input feild of current subject
      
      let val = document.getElementById(`${sub}Test${i+1}`).value;
      //check if input have a value so we push it into the vals array.
      if(val !== '') vals.push(val);
    }
    //getting average of all values using reduce
    let result = vals.reduce((ac,a) => ac + Number(a),0)/vals.length;
    //adding result(average) to the output of current subject.
    document.getElementById(`${sub}Average`).innerHTML = result
    //adding the average of current subject of the 'total' array.
    total.push(result);
  })
  //At last find the average of total averages and add it to 'finalGrade'
  total = total.filter(x => !isNaN(x));
  
  document.getElementById('finalGrade').innerHTML = total.reduce((ac,a) => ac + a,0)/total.length;
});
input{
  border-radius:5px;
  padding:3px;
  margin:5px;
  font-size:20px;
}
form{
  font-size:20px;
  font-family:sans-serif;
  text-transform:capitalize;
}
0 голосов
/ 07 марта 2019

Уже есть несколько решений.Вот мое.

В вашем коде есть что оптимизировать, и я думаю, что это хорошая идея - динамически создавать HTML на основе простого массива конфигурации, такого как

const subjects = [{
  name: 'science',
  numberOfTests: 3
}, {
  name: 'physics',
  numberOfTests: 2
}, {
  name: 'history',
  numberOfTests: 3
}];

, поэтому, еслименяются темы или количество тестов, вам не нужно менять код, а только эту конфигурацию.Я попытался прокомментировать мой пример кода, чтобы понять, что там делается.Но это не важная часть.Более важно то, что вам нужно понять, что происходит в части расчета, чтобы быть уверенным, что расчет правильный.Итак, я начну с этой части.

Если вы добавите атрибуты name к входам результатов теста и дадите каждому входу одного и того же субъекта одно и то же имя, вы можете легко получить NodeList этих входовпроверьте значения для каждого узла и рассчитайте на его основе.Итак, вы знаете значения и количество тестов, которые студент сдал по каждому предмету.

Давайте посмотрим

/* EventListener for the calculate button */
btn.addEventListener('click', function(e) {
  e.preventDefault(); // don't submit the form
  var totalAvSum = 0; // var for the total of all subject average totals 

  /* for all subjects in your configuration array */
  subjects.forEach(function(subject) {

    /* NodeList of all inputs with Name subject.name+'Test' */
    let subjResInputs = document.getElementsByName(subject.name+'Test');
    let testTotal = 0; // sum of test results
    let testCnt = 0; // number of tests the student took
    let tval; // value of input

    /* for each input of the subject */
    Array.prototype.map.call(subjResInputs, function(t){
      tval = (t.value * 1); // make sure, value is treated as number
      if (tval > 0) { // only if there is a value
        testTotal += tval; // add test result
        testCnt += 1; // increase test count
      }
    });

    /* calculate average and show it in output */
    totalAvSum += (testTotal/testCnt);
    document.getElementById(subject.name+'Average').textContent = (testTotal/testCnt);
  });

  /* after calculating average per subject show total average */
  document.getElementById('totalAverage').textContent = totalAvSum/subjects.length;    
});

Я использую document.getElementsByName () здесьполучить NodeList элементов ввода для каждого предмета.Затем я использую array.map () , чтобы просмотреть этот список.Чтобы проверить, имеет ли вход значение, я умножаю значение на 1 (что дает число) и вычисляю только, если результат больше 0.

Остальное - динамический материал для HTML.

/* This is your configuration.
   The form will be created based on that configuration.
   So you don't need to change anything in the code if 
   subjects or number of tests change. */
const subjects = [{
    name: 'science',
    numberOfTests: 3
  }, {
    name: 'physics',
    numberOfTests: 2
  }, {
    name: 'history',
    numberOfTests: 3
  }];

/* this functioncreates the form table */
function createFormTable() {
  var tr, td, txt, outp, btn, frmTbl;
    // frmTbl = document.getElementById('formTable');

  /* create table */
  frmTbl = document.createElement('table');
  frmTbl.setAttribute('id', 'formTable'); // set id to 'formTable'

  /* create table head */
  tr = document.createElement('tr');
  td = document.createElement('th');
  txt = document.createTextNode('subject');
  td.appendChild(txt);
  tr.appendChild(td);

  td = document.createElement('th');
  txt = document.createTextNode('test results');
  td.appendChild(txt);
  tr.appendChild(td); 

  td = document.createElement('th');
  txt = document.createTextNode('arith. mean');
  td.appendChild(txt);
  tr.appendChild(td);  

  /* add table head to table */
  frmTbl.appendChild(tr);

  /* create table row for each subject 
     the table row object is created in function createSubjectRow
     and here added to the table */
  subjects.forEach(function(subject) {
    frmTbl.appendChild(createSubjectRow(subject)); // add tr to table
  });

  /* row with total average */
  /* create tr element */
  tr = document.createElement('tr');

  td = document.createElement('th'); // td for text total
  td.setAttribute('colspan', 2);
  td.style.textAlign = 'right';
  txt = document.createTextNode('total'); // textNode
  td.appendChild(txt); // add textNode to td
  tr.appendChild(td); // add td to tr
  frmTbl.appendChild(tr); // add tr to table

  td = document.createElement('td'); // td for total average output  
  outp = document.createElement('output'); // create output element
  outp.setAttribute('id', 'totalAverage'); // set id
  td.appendChild(outp); // add output to td
  tr.appendChild(td); // add td to tr
  frmTbl.appendChild(tr); // add tr to table

  /* button */
  btn = document.createElement('button');
  btn.setAttribute('id', 'calcBtn');
  txt = document.createTextNode('calculate');
  btn.appendChild(txt);
  // document.getElementById('gradesForm').appendChild(btn);

  /* add button to last row in table */
  tr = document.createElement('tr');
  td = document.createElement('th'); // td for button
  td.setAttribute('colspan', 3);
  td.appendChild(btn); // add button to td
  tr.appendChild(td); // add td to tr
  frmTbl.appendChild(tr); // add tr to table

  /* EventListener for the calculate button */
  btn.addEventListener('click', function(e) {
    e.preventDefault(); // don't submit the form
    var totalAvSum = 0; // var for the total of all subject average totals 

    /* for all subjects in your configuration array */
    subjects.forEach(function(subject) {
      /* NodeList of all inputs with Name subject.name+'Test' */
      let subjResInputs = document.getElementsByName(subject.name+'Test');
      let testTotal = 0;
      let testCnt = 0;
      let tval;
      /* for each input of the subject */
      Array.prototype.map.call(subjResInputs, function(t){
        tval = (t.value * 1); // make sure, value is treated as number
        if (tval > 0) { // only if there is a value
          testTotal += tval; // add test result
          testCnt += 1; // increase test count
        }
      });
      /* calculate average and show it in output */
      totalAvSum += (testTotal/testCnt);
      document.getElementById(subject.name+'Average').textContent = (testTotal/testCnt);
    });
    /* after calculating average per subject
       show total average */
    document.getElementById('totalAverage').textContent = totalAvSum/subjects.length;    
  });

  return frmTbl;
}

function createSubjectRow(s) {
  var tr, td, txt, inp, outp; 

  /* create tr element */
  tr = document.createElement('tr');

  /* create td elements for subject s */
  td = document.createElement('td'); // td for subject name
  txt = document.createTextNode(s.name); // textNode
  td.appendChild(txt); // add textNode to td
  tr.appendChild(td); // add td to tr

  td = document.createElement('td'); // td for subject test results
  for (var i = 0; i < s.numberOfTests; i += 1) {
    inp = document.createElement('input'); // create input
    inp.setAttribute('type', 'number');  // set input type
    // inp.setAttribute('id', s.name + 'Test' + i); // set id
    /* set name attribute of input to subject name + 'Test'
       all test result inputs for the same subject will have the same name */
    inp.setAttribute('name', s.name + 'Test');
    inp.setAttribute('step', 0.1); // in case, you give grades like 3.5
    inp.setAttribute('min', 1);
    inp.setAttribute('max', 100);
    td.appendChild(inp); // add input to td
  }
  tr.appendChild(td); // add td to tr

  td = document.createElement('td'); // td for average output  
  outp = document.createElement('output'); // create output element
  outp.setAttribute('id', s.name + 'Average'); // set id
  td.appendChild(outp); // add output to td
  tr.appendChild(td); // add td to tr

  return tr; // return the resulting table row object
}

document.getElementById('gradesForm').appendChild(createFormTable());
  #formTable td {
    border: solid 1px #000;
    padding: 6px;
    border-spacing: 3px;
  }
  #formTable th {
    border: none;
    font-size:0.9em;
    text-align: left;
  }
  input[type="number"] {
    width: 4em;
    border: solid 1px #999;
    margin: 0 3px;
  }
<form id="gradesForm">
</form>
0 голосов
/ 06 марта 2019

Вместо того, чтобы делить его на 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;
});
<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...