skip to Main Content

I have a HTML table that consists of up to 25 rows.
A typical row:

function chkcountfn(required, el_id) {
  let memid = getid(el_id);
  let dateElement = "awarddate_" + memid;
  let datestr = document.getElementById(dateid).innerHTML
  let count = 0;

  // now need to go through all checkboxes with id of el_id and count those checked
  if (count >= required) {
    alert("Required number of skills acheived");
    if (datestr.length === 0) {
      var today = new Date();
      var dd = today.getDate();
      var mm = today.getMonth() + 1;
      var yyyy = today.getFullYear();
      if (dd < 10) {
        dd = '0' + dd;
      }
      if (mm < 10) {
        mm = '0' + mm;
      }
      today = dd + '/' + mm + '/' + yyyy;
      document.getElementById(dateid).innerHTML = today;
    }
  } else {
    document.getElementById(dateid).innerHTML = "";
  }
}

function getid(str) {
  var fields = str.split('_');
  var id = fields[1];
  return id;
}
<table>
  <tbody>
    <tr>
      <td id="128" name="name">Mike Starmer</td>
      <td><input type='checkbox' id='chk_128[0]' checked="checked" disabled="disabled" /></td>
      <td><input type='checkbox' id='chk_128[1]' checked="checked" disabled="disabled" /></td>
      <td><input type='checkbox' id='chk_128[2]' /></td>
      <td><input type='checkbox' id='chk_128[3]' /></td>
      <td><input type='checkbox' id='chk_128[4]' /></td>
      <td><input type='checkbox' id='chk_128[5]' checked="checked" disabled="disabled" /></td>
      <td><input type='checkbox' id='chk_128[6]' /></td>
      <td><input type='checkbox' id='chk_128[7]' /></td>
      <td><input type='checkbox' id='chk_128[8]' checked="checked" disabled="disabled" /></td>
      <td><input type='checkbox' id='chk_128[9]' /></td>
      <td id="passdate_128"> </td>
      <td id="awarddate_128"></td>
      <td hidden id="memid_128">128</td>
      <td hidden id="classid_128">7</td>
      <td hidden id="badgeid_128">7</td>
    </tr>
  </tbody>
</table>

I should add the table is constructed using PHP echo calls,

I am trying to add an onchange or onclick event to each checkbox that will count all the checked checkboxes in a row and show an alert if more than 80% are checked.

I have tried web searches on Javascript onchange and onclick functions, but all seem to relate to single checkbox.

So far I have come up with the following:

  1. for each checkbox add an onclick or onchange action that passes the checkbox id to the called function onclick="chkcountfn(8,this.id)" the 8 is the number of items needed to have checked.
  2. the function takes the passed id and then parses all checkboxes with that id counting those that are checked. If that number is =>80% then pop-up an alert, and write current date back to the rows "passdate_x".

To be honest I have checked the date substitution, which I found by searching this site, but have not managed to test anything else.

This is my first attempt at HTML/Javascript, and as you can see I am stuck on the looping through the checkboxes part and would also appreciate any helpful comments on what I have/am doing wrong. Also is it better to use an onchange or onclick event as I have been led to understand there are problems with some iPhones as they don’t associate checkboxes and click events.

2

Answers


  1. A simpler way to achieve your goal of only allowing 80% of the checkboxes on each row to be selected would be to simply get the boxes within the tr that had a checkbox update and compare the total number of checkboxes against the number which have been checked.

    Using this pattern you avoid the need for any convoluted code to target id attributes dynamically (which should be unique, just FYI) and also works for an infinite number of rows in your HTML.

    Here’s a working example:

    const checkboxChangeHandler = e => {
      const cb = e.target;
      const row = cb.closest('tr');
      const checkboxes = row.querySelectorAll('input[type="checkbox"]');
      const checked = Array.from(checkboxes).filter(cb => cb.checked);
      const maxAllowed = Math.floor(checkboxes.length * 0.8); // or Math.ceil()
      
      if (checked.length > maxAllowed) {
        cb.checked = false;
        console.log('too many checkboxes selected on this row');
      }
    }
    
    document.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.addEventListener('change', checkboxChangeHandler));
    <table>
      <tr>
        <td id="128" name="name">Mike Starmer</td>
        <td><input type="checkbox" name="chk_128[0]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128[1]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128[2]" /></td>
        <td><input type="checkbox" name="chk_128[3]" /></td>
        <td><input type="checkbox" name="chk_128[4]" /></td>
        <td><input type="checkbox" name="chk_128[5]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128[6]" /></td>
        <td><input type="checkbox" name="chk_128[7]" /></td>
        <td><input type="checkbox" name="chk_128[8]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128[9]" /></td>
        <td id="passdate_128"> </td>
        <td id="awarddate_128"></td>
        <td hidden id="memid_128">128</td>
        <td hidden id="classid_128">7</td>
        <td hidden id="badgeid_128">7</td>
      </tr>
      <tr>
        <td id="129" name="name">Mike Starmer</td>
        <td><input type="checkbox" name="chk_129[0]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129[1]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129[2]" /></td>
        <td><input type="checkbox" name="chk_129[3]" /></td>
        <td><input type="checkbox" name="chk_129[4]" /></td>
        <td><input type="checkbox" name="chk_129[5]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129[6]" /></td>
        <td><input type="checkbox" name="chk_129[7]" /></td>
        <td><input type="checkbox" name="chk_129[8]" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129[9]" /></td>
        <td id="passdate_129"> </td>
        <td id="awarddate_129"></td>
        <td hidden id="memid_129">129</td>
        <td hidden id="classid_129">7</td>
        <td hidden id="badgeid_129">7</td>
      </tr>
    </table>

    Note that the calculation includes the disabled checkboxes. This can easily be amended if they should be ignored.

    Login or Signup to reply.
  2. This is a typical use case for event delegation.

    …and rather than using an alert, it is preferable to use the one provided for managing HTML5 forms.
    Otherwise, if this is indeed a form, then this HTML code is not good.

    const myTable = document.querySelector('#my-table');
    
    myTable.onchange = ({target:elm}) =>  // global change for event delegation
      {
      if (!elm.matches('input[type="checkbox"]')) return  // get only changes on checkboxes elements
    
      let rowChkBx = [...elm.closest('tr').querySelectorAll('input[type="checkbox"]')].reduce((a,chkbx)=>
        {
        a.count++;
        if (chkbx.checked) a.checked++
        return a;
        },{count:0,checked:0});
    
      if ( rowChkBx.checked > (rowChkBx.count * .8))
        {
        elm.checked = false;
        alert('the 80% quota has already been reached!');
        }
      }
    html {
      font-family     : Arial, Helvetica, sans-serif;
      font-size       : 14px;
      }
    <table id="my-table">
      <tr>
        <td data-name="name">Mike Starmer 128</td>
        <td><input type="checkbox" name="chk_128-0" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128-1" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128-2" /></td>
        <td><input type="checkbox" name="chk_128-3" /></td>
        <td><input type="checkbox" name="chk_128-4" /></td>
        <td><input type="checkbox" name="chk_128-5" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128-6" /></td>
        <td><input type="checkbox" name="chk_128-7" /></td>
        <td><input type="checkbox" name="chk_128-8" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_128-9" /></td>
        <td id="passdate_128"> </td>
        <td id="awarddate_128"></td>
        <td hidden id="memid_128">128</td>
        <td hidden id="classid_128">7</td>
        <td hidden id="badgeid_128">7</td>
      </tr>
      <tr>
        <td id="129" name="name">Mike Starmer 129</td>
        <td><input type="checkbox" name="chk_129-0" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129-1" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129-2" /></td>
        <td><input type="checkbox" name="chk_129-3" /></td>
        <td><input type="checkbox" name="chk_129-4" /></td>
        <td><input type="checkbox" name="chk_129-5" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129-6" /></td>
        <td><input type="checkbox" name="chk_129-7" /></td>
        <td><input type="checkbox" name="chk_129-8" checked="checked" disabled="disabled" /></td>
        <td><input type="checkbox" name="chk_129-9" /></td>
        <td id="passdate_129"> </td>
        <td id="awarddate_129"></td>
        <td hidden id="memid_129">129</td>
        <td hidden id="classid_129">7</td>
        <td hidden id="badgeid_129">7</td>
      </tr>
    </table>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search