0

I came up with a very strange (for me) error today when it comes to html checkboxes. So, I have a table list with a checkbox in the end and a script to read the whole row for each selected checkbox. It is working fine, but I decided to add a "Select All" feature, and here is where things get weird. When I use the Select all, I receive an error and my object is empty.

Here is the code I am using for the select all:

c.transacoes = function() {


        $('input[type=checkbox]:checked').each(function() {

            var row = $(this).parent().parent();
            var rowcells = row.find('td');
            var chkdTransac = [];
            var obj = (g_form.getValue('u_transactions').length != 0) ? JSON.parse(g_form.getValue('u_transactions')) : [];;
            var i;
            for (i = 0; i < 5; i++) {
                chkdTransac[i] = rowcells[i].innerText;
            }
            
            obj.push({
                descricao_transacao: chkdTransac[1],
                valor_transacao: chkdTransac[2].replace(/-/g, ''),
                data: chkdTransac[3],
                ref_essence: chkdTransac[4],
                narrative: chkdTransac[5]
            });

            g_form.setValue('u_transactions', JSON.stringify(obj));
            c.modalInstance.close();

        });


    };

    toggle = function(source) {
        checkboxes = document.getElementsByName('cb1');
        for (var i = 0, n = checkboxes.length; i < n; i++) {
            checkboxes[i].checked = source.checked;
        }
    };
<div class="panel panel-default">
  <div class="panel-heading">
    <h4 class="panel-title">${Transactions}
     <button type="button" class="close" data-dismiss="modal" aria-label="Close" ng-click="c.closeModal()"> <span aria-hidden="true">&times;</span>
      </button></h4>
  </div>
 
  <div paging page="1" page-size="10" total="1000">
 
  <table id="table1" class="table table-bordered table-striped">
    <thead>
      <tr>
       <th>${Select}<input type="checkbox" onClick="toggle(this)" /></th>
       <th>${description}</th>
       <th>${Amount}</th>
       <th>${date}</th>
       <th>${reference}</th>
       <th>${Narrative}</th>
        <!--<th>${Select All}<input type="checkbox" onClick="toggle(this)" /></th> -->
        
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="transac in c.transactions">
        <td><input type="checkbox" name="cb1"></td>
        <td>{{transac.transaction.description}}</td>
        <td>{{transac.transaction.amount}}</td>
        <td>{{transac.transaction.date}}</td>
        <td>{{transac.transaction.reference}}</td>
        <td>{{transac.transaction.narrative}}</td>
      </tr>
    </tbody>
  </table>
     </div>

 <div class="panel-body">
    <div class="col-sm-4"></div>
    <div class="col-sm-4" style="align-items:center;">
      <div style="margin-bottom: 8px;">
      </div>
      <div>
        <button type="button" class="btn btn-primary btn-block" ng-click="c.transacoes()">${Use selected transactions}</button>
      </div>
    </div>
    <div class="col-sm-4"></div>
  </div>
</div>

The idea here is that a table with a list is generated dynamically with a checkbox that I later verify if it is checked and fill a multirow variable set (in ServiceNow) with the information. If I select manually the boxes, the code works perfectly, but if I use the select all, the following error message is trown:

"TypeError: Cannot read property 'innerText' of undefined"

You guys have any idea why this is happening and how to solve this?

Thanks in advance.

2 Answers2

2

I assume you meant to create multiple checkboxes and add a feature that will select all the checkboxes at once. If my assumption is correct, you will need to create more checkboxes and modify your function as follows:

function toggle(source) {
  // store all the checkboxes that named 'cb1[]' in an array
  var checkboxes = document.getElementsByName('cb1[]');;
  for (var i = 0; i < checkboxes.length; i++) {
    if (checkboxes[i] != source)
      // set true to the checked property of the rest of the checkboxes 
      checkboxes[i].checked = source.checked;
  }
}
<input type="checkbox" on onclick="toggle(this);" />Select all!<br />
<input type="checkbox" name='cb1[]' />checkbox 1<br />
<input type="checkbox" name='cb1[]' />checkbox 2<br />
<input type="checkbox" name='cb1[]' />checkbox 3<br />
<input type="checkbox" name='cb1[]' />checkbox 4<br />

Remember to "attach square brackets to the end of the name in order for server-side code to treat checked checkboxes as an array. Otherwise only the last checked item in the group would be available upon submission" (source: dyn-web.com).

Original code is from the following response where querySelectorAll is used instead of getElementsByName: How to implement “select all” check box in HTML?

Mari Goto
  • 81
  • 6
  • in valid HTML, checkboxes can't have the same name... – Mister Jojo Jun 04 '21 at 15:31
  • 1
    Good point, @MisterJojo. Even though w3c states that "Several checkboxes in a form may share the same control name." You would need to "attach square brackets to the end of the name in order for server-side code to treat checked checkboxes as an array" (source: [dyn-web.com](http://dyn-web.com/tutorials/forms/checkbox/same-name-group.php)). – Mari Goto Jun 05 '21 at 11:28
0

Ok, so I figured out that where some "trash" before my rows when I used the "select all" checkbox, so I made a small change in the c.transacoes function to ignore those undefined and it is working.

Here is the final function:

c.transacoes = function() {

        $('input[type=checkbox]:checked').each(function() {

            var row = $(this).parent().parent();
            var rowcells = row.find('td');
            var chkdTransac = [];
            var obj = (g_form.getValue('u_transactions').length != 0) ? JSON.parse(g_form.getValue('u_transactions')) : [];;
            var i;
            for (i = 0; i < 6; i++) {

                if (rowcells[i] == undefined) {
                    return;
                } else {
                    chkdTransac[i] = rowcells[i].innerText;
                }

            }

            var date = chkdTransac[3].split("T");

            obj.push({
                descricao_transacao: chkdTransac[1],
                valor_transacao: chkdTransac[2].replace(/-/g, ''),
                data: date[0],
                ref_essence: chkdTransac[4],
                narrative: chkdTransac[5]
            });

            g_form.setValue('u_transactions', JSON.stringify(obj));
            c.modalInstance.close();

        });

    };