javascripthtmlprogress-bartaskmanager

How to increment length based on the number of checkboxes in a table to find perecntage?


Trying to make a task manager and implement a circular progress bar that correlates to the checkboxes. I got it to where I have a add row button and it seems to work fine but when I try to link it to the progress bar I usually get an error that the variable is not defined.

Here is my current HTML and JS.

//CHECKING IF THE CHECKBOXES HAVE BEEN CHECKED OR UNCHECKED AND THEN RETURNING THE NUMBER
//AS VALCHECKCOUNT
var valCheckCount = 0;

function update() {

  let checkboxCounter = document.querySelectorAll('input[name="dailyCheck"]:checked');
  valCheckCount = checkboxCounter.length;
  return valCheckCount;
};

let checkboxCounter = document.querySelectorAll('input[name="dailyCheck"]');
checkboxCounter.forEach(function(checkboxD) {
  checkboxD.addEventListener("change", function(e) {
    update();
  });
});

function addRowFunction() {
  var progressLength = document.querySelectorAll('input[name="dailyCheck"]');
  var parentTable = document.getElementById("table1");
  var myTd, myInputCheck, myInputText;
  var myTr = document.createElement('tr');
  myTr.setAttribute('class', 'unit-table');
  for (var j = 0; j < 1; j++) {
    myTd = document.createElement('td');
    myInputText = document.createElement('input');
    myInputText.setAttribute('type', 'text');
    myTd.appendChild(myInputText);
    myTr.appendChild(myTd);
  }
  for (var i = 0; i < 31; i++) {
    myTd = document.createElement('td');
    myInputCheck = document.createElement('input');
    myInputCheck.setAttribute('type', 'checkbox');
    myInputCheck.setAttribute('name', 'dailyCheck');
    myInputCheck.addEventListener('change', function(e) {
      update();
    });
    myTd.appendChild(myInputCheck);
    myTr.appendChild(myTd);
  }
  parentTable.appendChild(myTr);
  return progressLength.length;
}



//ALL OF THE CODE USED TO CREATE THE CIRCULAR PROGRESS BAR AND TAKES THE INPUT FROM
//VALCHECKCOUNT AND THE FUNCTION ABOVE.
let circularProgress = document.querySelector(".circular-progress"),
  progressValue = document.querySelector(".progress-value");


let progressStartValue = 0,
  progressEndValue = valCheckCount,
  speed = 20;
let progressLength = document.querySelectorAll('input[name="dailyCheck"]').length;

let progress = setInterval(() => {
  progressStartValue++;
  let percentageAnswer = Math.round((valCheckCount / progressLength) * 100);

  progressValue.textContent = `${percentageAnswer}%`
  circularProgress.style.background = `conic-gradient(#7d2ae8 ${percentageAnswer * 3.6}deg, #ededed 0deg)`

  if (progressStartValue == percentageAnswer) {
    clearInterval(progress);
  }
}, speed);
<body>
  <h1>Task Manager</h1>
  <!--Table for Weekly Habits-->
  <h2>Weekly Habits</h2>

  <!--Circular Progress Tracker for Daily habits-->
  <div class="container">
    <div class="circular-progress">
      <span class="progress-value" onchange="valCheckCount(this)">0%</span>
    </div>
    <span class="text">Daily Habits</span>
  </div>
  <div id="root">


  </div>
  <!--Creating table format for Dialy Tasks-->
  <div id="dailyTable">
    <table id="table1" class="dailyT">

      <!--first table header for title and days-->
      <tr class="unit-table">
        <td>
          <label for="firstRow">Daily Habits</label>
        </td>
        <td>
          <label for="firstRow">1</label>
        </td>
        <td>
          <label for="firstRow">2</label>
        </td>
        <td>
          <label for="firstRow">3</label>
        </td>
        <td>
          <label for="firstRow">4</label>
        </td>
        <td>
          <label for="firstRow">5</label>
        </td>
        <td>
          <label for="firstRow">6</label>
        </td>
        <td>
          <label for="firstRow">7</label>
        </td>
        <td>
          <label for="firstRow">8</label>
        </td>
        <td>
          <label for="firstRow">9</label>
        </td>
        <td>
          <label for="firstRow">10</label>
        </td>
        <td>
          <label for="firstRow">11</label>
        </td>
        <td>
          <label for="firstRow">12</label>
        </td>
        <td>
          <label for="firstRow">13</label>
        </td>
        <td>
          <label for="firstRow">14</label>
        </td>
        <td>
          <label for="firstRow">15</label>
        </td>
        <td>
          <label for="firstRow">16</label>
        </td>
        <td>
          <label for="firstRow">17</label>
        </td>
        <td>
          <label for="firstRow">18</label>
        </td>
        <td>
          <label for="firstRow">19</label>
        </td>
        <td>
          <label for="firstRow">20</label>
        </td>
        <td>
          <label for="firstRow">21</label>
        </td>
        <td>
          <label for="firstRow">22</label>
        </td>
        <td>
          <label for="firstRow">23</label>
        </td>
        <td>
          <label for="firstRow">24</label>
        </td>
        <td>
          <label for="firstRow">25</label>
        </td>
        <td>
          <label for="firstRow">26</label>
        </td>
        <td>
          <label for="firstRow">27</label>
        </td>
        <td>
          <label for="firstRow">28</label>
        </td>
        <td>
          <label for="firstRow">29</label>
        </td>
        <td>
          <label for="firstRow">30</label>
        </td>
        <td>
          <label for="firstRow">31</label>
        </td>
      </tr>

    </table>
    <br>

    <button type="button" id="addRowButton" onClick="addRowFunction()">+</button>

  </div>
</body>


Solution

  • Move let progressLength = document.querySelectorAll('input[name="dailyCheck"]').length; inside the setInterval function. There is no input[name="dailyCheck"] on page load, so progressLength always is zero.

    //CHECKING IF THE CHECKBOXES HAVE BEEN CHECKED OR UNCHECKED AND THEN RETURNING THE NUMBER
    //AS VALCHECKCOUNT
    var valCheckCount = 0;
    
    function update() {
    
      let checkboxCounter = document.querySelectorAll('input[name="dailyCheck"]:checked');
      valCheckCount = checkboxCounter.length;
      return valCheckCount;
    };
    
    let checkboxCounter = document.querySelectorAll('input[name="dailyCheck"]');
    checkboxCounter.forEach(function(checkboxD) {
      checkboxD.addEventListener("change", function(e) {
        update();
      });
    });
    
    function addRowFunction() {
      var progressLength = document.querySelectorAll('input[name="dailyCheck"]');
      var parentTable = document.getElementById("table1");
      var myTd, myInputCheck, myInputText;
      var myTr = document.createElement('tr');
      myTr.setAttribute('class', 'unit-table');
      for (var j = 0; j < 1; j++) {
        myTd = document.createElement('td');
        myInputText = document.createElement('input');
        myInputText.setAttribute('type', 'text');
        myTd.appendChild(myInputText);
        myTr.appendChild(myTd);
      }
      for (var i = 0; i < 31; i++) {
        myTd = document.createElement('td');
        myInputCheck = document.createElement('input');
        myInputCheck.setAttribute('type', 'checkbox');
        myInputCheck.setAttribute('name', 'dailyCheck');
        myInputCheck.addEventListener('change', function(e) {
          update();
        });
        myTd.appendChild(myInputCheck);
        myTr.appendChild(myTd);
      }
      parentTable.appendChild(myTr);
      return progressLength.length;
    }
    
    
    
    //ALL OF THE CODE USED TO CREATE THE CIRCULAR PROGRESS BAR AND TAKES THE INPUT FROM
    //VALCHECKCOUNT AND THE FUNCTION ABOVE.
    let circularProgress = document.querySelector(".circular-progress"),
      progressValue = document.querySelector(".progress-value");
    
    
    let progressStartValue = 0,
      progressEndValue = valCheckCount,
      speed = 20;
    //let progressLength = document.querySelectorAll('input[name="dailyCheck"]').length;
    
    let progress = setInterval(() => {
      let progressLength = document.querySelectorAll('input[name="dailyCheck"]').length;
      
      progressStartValue++;
      let percentageAnswer = Math.round((valCheckCount / progressLength) * 100);
    
      progressValue.textContent = `${percentageAnswer}%`
      circularProgress.style.background = `conic-gradient(#7d2ae8 ${percentageAnswer * 3.6}deg, #ededed 0deg)`
    
      if (progressStartValue == percentageAnswer) {
        clearInterval(progress);
      }
    }, speed);
    <body>
      <h1>Task Manager</h1>
      <!--Table for Weekly Habits-->
      <h2>Weekly Habits</h2>
    
      <!--Circular Progress Tracker for Daily habits-->
      <div class="container">
        <div class="circular-progress">
          <span class="progress-value" onchange="valCheckCount(this)">0%</span>
        </div>
        <span class="text">Daily Habits</span>
      </div>
      <div id="root">
    
    
      </div>
      <!--Creating table format for Dialy Tasks-->
      <div id="dailyTable">
        <table id="table1" class="dailyT">
    
          <!--first table header for title and days-->
          <tr class="unit-table">
            <td>
              <label for="firstRow">Daily Habits</label>
            </td>
            <td>
              <label for="firstRow">1</label>
            </td>
            <td>
              <label for="firstRow">2</label>
            </td>
            <td>
              <label for="firstRow">3</label>
            </td>
            <td>
              <label for="firstRow">4</label>
            </td>
            <td>
              <label for="firstRow">5</label>
            </td>
            <td>
              <label for="firstRow">6</label>
            </td>
            <td>
              <label for="firstRow">7</label>
            </td>
            <td>
              <label for="firstRow">8</label>
            </td>
            <td>
              <label for="firstRow">9</label>
            </td>
            <td>
              <label for="firstRow">10</label>
            </td>
            <td>
              <label for="firstRow">11</label>
            </td>
            <td>
              <label for="firstRow">12</label>
            </td>
            <td>
              <label for="firstRow">13</label>
            </td>
            <td>
              <label for="firstRow">14</label>
            </td>
            <td>
              <label for="firstRow">15</label>
            </td>
            <td>
              <label for="firstRow">16</label>
            </td>
            <td>
              <label for="firstRow">17</label>
            </td>
            <td>
              <label for="firstRow">18</label>
            </td>
            <td>
              <label for="firstRow">19</label>
            </td>
            <td>
              <label for="firstRow">20</label>
            </td>
            <td>
              <label for="firstRow">21</label>
            </td>
            <td>
              <label for="firstRow">22</label>
            </td>
            <td>
              <label for="firstRow">23</label>
            </td>
            <td>
              <label for="firstRow">24</label>
            </td>
            <td>
              <label for="firstRow">25</label>
            </td>
            <td>
              <label for="firstRow">26</label>
            </td>
            <td>
              <label for="firstRow">27</label>
            </td>
            <td>
              <label for="firstRow">28</label>
            </td>
            <td>
              <label for="firstRow">29</label>
            </td>
            <td>
              <label for="firstRow">30</label>
            </td>
            <td>
              <label for="firstRow">31</label>
            </td>
          </tr>
    
        </table>
        <br>
    
        <button type="button" id="addRowButton" onClick="addRowFunction()">+</button>
    
      </div>
    </body>

    By the way, the code inside tha setInterval could be inside the update function. Running that code every 20ms when there is no change at all is useless.