Search code examples
javascripthtml-tableappend

Cloned/Appended HTML Table Row Checkboxes Changing Source Checkboxes


First Off I want to just say I am new to Javascript and programming in general so your answers have to be for non-experienced person. Thanks.

I have two HTML tables, the left is the source the right is the destination table. I'm using javascript to Clone/Append the table row from source to destination, this works perfectly. The row has four checkboxes, after appending the row to the destination, the checkbox will change the checkbox in the source table corresponding to the location.

EX: if I click the checkbox on the third row in the destination table the checkbox of the third row in the source changes which is a different row of information altogether. The javascript I use removes the row from source when appending the destination table. I have tried different scripts for cloning and appending table rows, however the same result happens. Is this result normal and how would I work around it? If this result can not be corrected, is there a way to disable the cloned checkboxes in the destination table and leave the source checkboxes functional?

This is the script I'm using to Clone/Append the row. As I stated I have tried numerious different scripts and I get the same result.

#equipTable button::after {content: "Select"}
#rentTable button::after {content: "Remove"}  


const moveTR = (ev) => {
  const EL_tr = ev.currentTarget.closest("tr");
  const sel = EL_tr.closest("table").id === "equipTable" ? "#rentTable" : "#equipTable";
  document.querySelector(sel + " tbody").append(EL_tr);
  sortTable1();
  sortTable2();
};

document.querySelectorAll("table button")
  .forEach(EL => EL.addEventListener("click", moveTR));

This is the code that populates the equipTable.

<?php

include_once "application/dbh.inc.php";

       $sql = "SELECT * FROM housekeeping INNER JOIN sites ON sitesSite=housekeeping.Cabin
                  WHERE sitesCategory='Cabin'
                  ORDER BY sitesSort ASC
                  ";

       $result = mysqli_query($conn, $sql);
       if(mysqli_num_rows($result)>0)
       {
         $tblrow = 0;
         $number = 0;
         $items = array ();
         while($row = mysqli_fetch_array($result)){
         $number++;
         $tblrow++;
         $tblrow;

         $checked = ($row['KeyLoc']) ? 'checked="checked"' : ''; //see ternary operator
         $checked1 = ($row['HeatLoc']) ? 'checked="checked"' : ''; //see ternary operator
         $checked2 = ($row['Priority']) ? 'checked="checked"' : ''; //see ternary operator
         $checked4 = ($row['LinenRental']) ? 'checked="checked"' : ''; //see ternary operator

 ?>

<tr id= "idTr" class="row">
    <!--<td hidden id="IDRow"><?php echo $tblrow; ?></td> -->
    <td hidden id="IDSort"><?php echo $row['sitesSort']; ?></td>
    <td id="IDCabin"><?php echo $row['Cabin']; ?></td>

    <td><input type='checkbox' onclick='$keyfalse' name='key' value='1' onchange='update_value(this);'</td>
    <td><input type='checkbox' onclick='$heatfalse' name='heat' value='1' onchange='update_value1(this);'</td>
    <td><input type='checkbox' onclick='$priorityfalse' name='priority' value='1' onchange='update_value2(this);'</td>
    <td><input type='checkbox' onclick='$linenfalse' name='linen' value='1' onchange='update_value4(this);'</td>
    
    <td hidden><?php echo $row['AssignRecID']; ?>"</td>
    <td><button type="button"></button></td>
</tr>
    <?php }} ?>

Here is the code I use to get the checkbox status.

function update_value(chk_bx){
    document.getElementById('info').innerHTML = (chk_bx.parentNode.parentNode.rowIndex);
        var myTab = document.getElementById('equipTable');

        // this is the row selection
        var objCells = myTab.rows.item(chk_bx.parentNode.parentNode.rowIndex).cells;

        // this is the column selection for sortorder first cell in row
        var _$sort = objCells.item(0).innerHTML;

        // this is the column selection for cabin number second cell in row
        var _$t = objCells.item(1).innerHTML;
        // var _$t = objCells.item(1).innerHTML;
                    if(chk_bx.checked)
                    {
                            var a="1";}
                    else{
                            var a="0";
                    }
                    document.getElementById('result').innerHTML = a;

              // alert("Keyloc is " + a);

              $.ajax({
                    url:'includes/cbnkeychkbox-update.inc.php',
                    method:'POST',
                    data:{
                        cabin:_$t,
                        keyloc:a

                    },
                    success:function(response){
                        //  alert(response);

                    }
                });
        }

This is the code that is called from above code:

The file name is cbnkeychkbox-update.inc.php

<?php
include_once '../application/dbh.inc.php';

$cabin = $_POST['cabin'];
$keyloc = $_POST['keyloc'];

$sql="UPDATE housekeeping set KeyLoc='$keyloc' where Cabin='$cabin'";
if($conn->query($sql)===TRUE){
    echo "DATA updated";
}

?>

I use this in other areas of the application and it works well. I'm sure there is a much better way to do this but I'm learning as I go.

Here is the database table structure:

CREATE TABLE housekeeping ( ID int(11) Not Null PRIMARY AUTO_INCREMENT, Cabin varchar(25), KeyLoc tinyint(1), HeatLoc tinyint(1), Priority tinyint(1), LinenRental tinyint(1) );

INSERT INTO housekeeping(Cabin) VALUES ('236'), ('502'), ('503'), ('504') ;

CREATE TABLE sites ( sitesID int(11) NOT Null PRIMARY AUTO_INCREMENT, sitesSort varchar(25), sitesSite varchar(25), sitesDescription varchar(250), sitesCategory varchar(25) );

INSERT INTO sites(sitesSort, sitesSite, sitesDescription, sitesCategory) VALUES ('00236', '236'), ('00502', '502'), ('00503', '503'), ('00504', '504') ;


Solution

  • Unable to reproduce

    The issue could not be reproduced based on the information provided. The posted code does what it appears to be written to do: clicking select moves a table row to the rent table, and clicking remove moves a table row to equipment table.

    Initial setup: #equipTable is populated and #rentTable is empty, table sort not tested.

    Results obtained: When moved, the status of checkboxes in a row is not altered, and clicking them operates on the checkbox clicked.

    The effects described in the post appear to be caused by code in other parts of the app, not included in the post. Subject to further information, I may be able to delete or update this reply accordingly. Feel free to adapt the test HTML generation in the snippet below if it helps create a reproducible example of the issue.

    "use strict";
    // generate test HTML ---------------------------
    const tableIds = ["equipTable", "rentTable"];
    
    let cb_number = 1;
    for( let container = 0; container <=1; ++container) {
      const div = document.createElement('div');
      div.className = "container";
      div.innerHTML = `<table id="${tableIds[container]}"><tbody></tbody></table>`;
      const table = div.querySelector("table");
      const tbody = table.querySelector("tbody");
    
      if( container==0) {
        for( let row = 1; row < 5; ++row) {
          let tr = `<tr><td><button type='button'></button></td>`;
          for(let cb = 0; cb<4; ++cb) {
            tr +=`<td><label>Checkbox ${cb_number++} <input type="checkbox"></label>
               </td>\n`;
          }
          tr += "</tr>\n";
          tbody.insertAdjacentHTML("beforeend", tr);
        }
      }
      div.innerHTML =`<h3>#${table.id}:`;
      div.append( table);
      document.body.append(div);
    }
    
     // dummy table sort
    
     let warned = false;
     function sortTable1() {
       if(!warned) {
         console.log("table sort not tested");
         warned = true;
       }
     }
     const sortTable2 = sortTable1;
    
    
    // ------------------------
    // test posted code
       
    const moveTR = (ev) => {
      const EL_tr = ev.currentTarget.closest("tr");
      const sel = EL_tr.closest("table").id === "equipTable" ? "#rentTable" : "#equipTable";
      document.querySelector(sel + " tbody").append(EL_tr);
      sortTable1();
      sortTable2();
    };
    
    document.querySelectorAll("table button")
      .forEach(EL => EL.addEventListener("click", moveTR));
    #equipTable button::after {content: "Select"}
    #rentTable button::after {content: "Remove"}
    .container { display: inline-block; width: fit-content} 
    table  {padding: 1rem; margin-left: 1rem;}


    Response to post updates.

    Some suggested changes to the PHP:

    • define $cabin, $sitesSort and $AssignRecID in PHP for readability (by extracting $row fields in one place).
    • remove/comment out table row HTML lines that generate multiple rows with the same id - this is invalid HTML.
    • record row specific data as data attributes of row elements (<tr> tags). Values from the database must be valid HTML attribute values. If this is a problem you could go back to putting values in the HTML content of hidden row data cells (ouch), or look into escaping row data values in PHP before placing them in the generated document.
    • remove reference to front end table row rowIndex properties. These change as rows are selected and removed from their parent table.

    The purpose of these changes is to allow front end code that handles check box events to methodically find

    • id of the check box's parent table: event.target.closest('table').id
    • row data of the check box: event.target.closest('tr').dataset
    • individual values as dataset.number, dataset.siteSort, dataset.cabin, and dataset.AssignRecID.

    Note 1: the text values of PHP variables used as onclick attributes of checkboxes on the front end should pass event to the handlers called. E.G.

      $keyfalse = "keyfalseHandler(event)"; // not "keyfalseHandler()" with no argument.
    

    Note 2: Row values $number and $tableRow are the same and appear to be the ordinals of the sorted database items. Not sure if passing both $siteSort and the sorted row index to the front end is necessary.

    I have not had a chance (and might not get one) to look at the front end closely. I suspect it should clear checkboxes and update the database if rent rows are removed (or something), but can't say what exactly from a business perspective.

    Not sure where _t comes from, perhaps it is what I have called dataset.cabin on the front end.

    <?php
    
    include_once "application/dbh.inc.php";
    
           $sql = "SELECT * FROM housekeeping INNER JOIN sites ON sitesSite=housekeeping.Cabin
                      WHERE sitesCategory='Cabin'
                      ORDER BY sitesSort ASC
                      ";
    
           $result = mysqli_query($conn, $sql);
           if(mysqli_num_rows($result)>0)
           {
             $tblrow = 0;
             $number = 0;
             $items = array ();
             while($row = mysqli_fetch_array($result)){
             $number++;
             $tblrow++;
             $tblrow;
     
             $checked = ($row['KeyLoc']) ? 'checked="checked"' : ''; //see ternary operator
             $checked1 = ($row['HeatLoc']) ? 'checked="checked"' : ''; //see ternary operator
             $checked2 = ($row['Priority']) ? 'checked="checked"' : ''; //see ternary operator
             $checked4 = ($row['LinenRental']) ? 'checked="checked"' : ''; //see ternary operator
             // and 
             $cabin = $row['cabin')
             $sitesSort = $row['sitesSort']
             $AssignRecID = $row['AssignRecID'
    
     ?>
    
    <tr class="row"
       data-number="<?php echo $number; ?>" data-sitesort="<?php echo $sitesSort; ?>"
       data-cabin="<?php echo $cabin; ?>" data-AssignRecID="<?php echo $AssignRecID; ?>"
    >
        <!--<td hidden id="IDRow"><?php echo $tblrow; ?></td> -->
        <!--<td hidden id="IDSort"><?php echo $row['sitesSort']; ?></td> -->
        <!--<td id="IDCabin"><?php echo $row['Cabin']; ?></td> -->
    
        <td><input type='checkbox' onclick='$keyfalse' name='key' value='1' onchange='update_value(this);'</td>
        <td><input type='checkbox' onclick='$heatfalse' name='heat' value='1' onchange='update_value1(this);'</td>
        <td><input type='checkbox' onclick='$priorityfalse' name='priority' value='1' onchange='update_value2(this);'</td>
        <td><input type='checkbox' onclick='$linenfalse' name='linen' value='1' onchange='update_value4(this);'</td>
        
        <!--<td hidden><?php echo $row['AssignRecID']; ?>"</td> -->
    
        <td><button type="button"></button></td>
    </tr>
        <?php }} ?>
    

    Please fix any syntax errors or logic you don't agree with - it's a long time since I've read or modified any PHP.