Home > Enterprise >  How to push values into an array and find their average
How to push values into an array and find their average

Time:07-27

I'm trying to create a function which takes an array and returns the average of it. The Id argument is the html id that I've passed into the function.

I don't know why but I am getting an error:

script.js:12 Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')
    at avgFinder (script.js:12:12)
    at HTMLButtonElement.onclick (one.html:21:49)

let array = [];

const addToarray = (id) => {
    return array.push(id);
};
    
const avgFinder = () => {
    let total = 0;
    let count = 0;
    array.forEach(item => {
        total  = item;
        count  ;
    });   
    console.log(total / count);
    return total / count;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="script.js"></script>
</head>
<body>
    <div id="1" onclick="addToarray(1)">1</div>
    <div id="2" onclick="addToarray(2)">2</div>
    <div id="3" onclick="addToarray(3)">3</div>
    <div id="4" onclick="addToarray(4)">4</div>
    <div id="5" onclick="addToarray(5)">5</div>
    <div id="6" onclick="addToarray(6)">6</div>
    <div id="7" onclick="addToarray(7)">7</div>
    <div id="8" onclick="addToarray(8)">8</div>
    <div id="9" onclick="addToarray(9)">9</div>
    <div id="10" onclick="addToarray(10)">10</div>
    <button  onclick="avgFinder()">Click me</button>
</body>
</html>

CodePudding user response:

Your avgFinder = (arr) => { expects an arr Array, instead you're passing... nothing.
Also, let total = 0; cannot be a hardcoded 0. It should be your array.length instead.

Here's a fix with best practices:

  • Avoid using inline HTML on* JS handlers. Use the proper addEventListener() isnstead. JS should be in one place only, and that's the respective tag or file.
  • Use data-* attribute to store arbitrary data that can be used in JavaScript.
  • Use Array.prototype.reduce to reduce an Array to Number.
  • Avoid polluting the GlobalThis scope by using window or undeclared variables. Try always to use const, or let when a value is expected to be changed at a later time.

// DOM utility functions:

const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);


// Task: Find average:

const elsDataId = els("[data-id]");
const elAvgFinder = el("#avgFinder");
const elItems = el("#items");
const elResult = el("#result");

const array = [];

const addToArray = (n) => array.push(n);

const avgFinder = () => {
  const count = array.reduce((acc, n) => acc   n, 0);
  const avg = count / array.length;
  elItems.value = array;
  elResult.value = avg;
  return avg
}

elsDataId.forEach((elDataId) => {
  elDataId.addEventListener("click", () => addToArray( elDataId.dataset.id));
});

elAvgFinder.addEventListener("click", avgFinder);
<button data-id="1" type="button">1</button>
<button data-id="2" type="button">2</button>
<button data-id="3" type="button">3</button>
<button data-id="4" type="button">4</button>
<button data-id="5" type="button">5</button>
<button data-id="6" type="button">6</button>
<button data-id="7" type="button">7</button>
<button data-id="8" type="button">8</button>
<button data-id="9" type="button">9</button>
<button data-id="10" type="button">10</button>

<button id="avgFinder" type="button">Calculate Avg</button><br>
Items: <input id="items" type="text" readonly><br>
Average: <input id="result" type="text" readonly>

CodePudding user response:

Previous edits of this answer gave a solution that was less than idea. The following addresses those:

  • No pollution of globalThis
  • Does not mix functionality with markup
  • Does not mix data with functionality

// wrapping function to avoid poluting globalThis
(function(){

  // data-store for values
  let arr = [];

  // Loop over each button that has a data-id
  document.querySelectorAll('button[data-id]').forEach(ele => {

    // Add event listener: when clicked add the button's value to the array
    ele.addEventListener('click', () => arr.push(Number(ele.dataset.id)));
  });
 
  // Get a reference to the result element
  const averageEle = document.getElementById('result');

  // Add event listener for when the average button is clicked
  document
    .getElementById('avgFinder')
    .addEventListener('click', () => {

      // no values to average
      if (arr.length === 1) {
          averageEle.value = 0;

      // nothing to average 
      } else if (arr.length === 1) {
          averageEle.value = arr[0];

      } else {

        const sum = arr.reduce((prev, cur) => prev   cur);
        const average = sum / arr.length;
        
        averageEle.value = average;
      }
    });
 
})();
<button data-id="1" type="button">1</button>
<button data-id="2" type="button">2</button>
<button data-id="3" type="button">3</button>
<button data-id="4" type="button">4</button>
<button data-id="5" type="button">5</button>
<button data-id="6" type="button">6</button>
<button data-id="7" type="button">7</button>
<button data-id="8" type="button">8</button>
<button data-id="9" type="button">9</button>
<button data-id="10" type="button">10</button>
<button id="avgFinder" type="button">Calculate Avg</button><br>
Average: <input id="result" type="text" value="0" readonly>

  • Related