M.Gooda
M.Gooda

Reputation: 137

How to select only one row in table with checkbox

I have a table with x numbers of rows and 4 columns, one column is checkbox and other three are readonly selectboxs. I want the user to select just 1 row to be editable by checking checkbox in first column then if he check another checkbox in another row, the checkbox he previously checked get unchecked and row get readonly again.

So I want the user to select 1 row only to edit and others be readonly. here is my code but it is not working.

$(document).ready(function(){
  $('.col1, .col2, .col3').attr('disabled', true)
   selectRow();
    $('.tbl').on('change', '.selectRow', selectRow);
    function selectRow() {
     $('.tbl tbody tr').each(function () {
     $(this).find('.selectRow').each(function () {
      var checkedRow = $(this).closest('tr').find('input:checkbox:checked'),
        col1 = $(this).closest('tr').find('.col1'),
        col2 = $(this).closest('tr').find('.col2'),
        col3 = $(this).closest('tr').find('col3');
        if (checkedRow){
        $('.col1, .col2, .col3').removeAttr('disabled')
    checkedRow.siblings().prop('checked', false);
    }else{
        $('.col1, .col2, .col3').attr('disabled', true)
    checkedRow.siblings().prop('checked', false);
    }
 });
});
}
});
<table class="tbl">
<tr>
  <td><input type="checkbox" name="check1" class = "selectRow" />&nbsp;</td>
  <td>
   <select class="col1">
       <option id="col1o1">A</option>
       <option id="col1o2">B</option>
       <option id="col1o3">C</option>
       <option id="col1o4">E</option>
   </select>
  </td>
    <td>
   <select class="col2">
       <option id="col2o1">A</option>
       <option id="col2o2">B</option>
       <option id="col2o3">C</option>
       <option id="col2o4">E</option>
   </select>
  </td>
    <td>
   <select class="col3">
       <option id="col3o1">A</option>
       <option id="col3o2">B</option>
       <option id="col3o3">C</option>
       <option id="col3o4">E</option>
   </select>
  </td>
</tr>
<br>
<tr>
  <td><input type="checkbox" name="check1" />&nbsp;</td>
  <td>
   <select class="s1">
       <option id="s1o1">A</option>
       <option id="o2">B</option>
       <option id="o3">C</option>
       <option id="o4">E</option>
   </select>
  </td>
    <td>
   <select class="s2">
       <option id="s2o1">A</option>
       <option id="s2o2">B</option>
       <option id="s2o3">C</option>
       <option id="s2o4">E</option>
   </select>
  </td>
    <td>
   <select class="s3">
       <option id="s3o1">A</option>
       <option id="s3o2">B</option>
       <option id="s3o3">C</option>
       <option id="s3o4">E</option>
   </select>
  </td>
</tr>
<br>
<tr>
  <td><input type="checkbox" name="check1" />&nbsp;</td>
  <td>
   <select class="s1">
       <option id="s1o1">A</option>
       <option id="o2">B</option>
       <option id="o3">C</option>
       <option id="o4">E</option>
   </select>
  </td>
    <td>
   <select class="s2">
       <option id="s2o1">A</option>
       <option id="s2o2">B</option>
       <option id="s2o3">C</option>
       <option id="s2o4">E</option>
   </select>
  </td>
    <td>
   <select class="s3">
       <option id="s3o1">A</option>
       <option id="s3o2">B</option>
       <option id="s3o3">C</option>
       <option id="s3o4">E</option>
   </select>
  </td>
</tr>
</table>

this is my code:

Upvotes: 0

Views: 1671

Answers (3)

KooiInc
KooiInc

Reputation: 122888

Without jQuery and using event delegation things may be somewhat simpler:

document.addEventListener(`click`, handle);

// disable all selectors initially
document.querySelectorAll(`td select`)
  .forEach(s => s.setAttribute(`disabled`, true));

function handle(evt) {
  // only do something if a checkbox was clicked
  if (evt.target.type === `checkbox`) {
    const isChecked = evt.target.checked;
    const selectedRow = evt.target.closest(`tr`);
    // reset checkboxes, row coloring and disabled state
    document.querySelectorAll(`input[type='checkbox']`)
      .forEach(cb => {
        cb.checked = cb !== evt.target ? false : isChecked;
        const row = cb.closest(`tr`);
        row.classList[isChecked && row === selectedRow ?
          `add` : `remove`](`selected`);
        [...row.querySelectorAll(`select`)].filter(r => r !== selectedRow)
          .forEach(s => s.setAttribute(`disabled`, true));
        selectedRow.querySelectorAll(`select`)
          .forEach(s => s[isChecked ? 
              `removeAttribute` : `setAttribute`](`disabled`, true));
      });
  }
}
body {
  margin: 2rem;
}

tr.selected {
  background-color: lightgreen;
}
<table class="tbl">
  <tr>
    <td><input type="checkbox" name="check1" class="selectRow" />&nbsp;</td>
    <td>
      <select class="col1">
        <option id="col1o1">A</option>
        <option id="col1o2">B</option>
        <option id="col1o3">C</option>
        <option id="col1o4">E</option>
      </select>
    </td>
    <td>
      <select class="col2">
        <option id="col2o1">A</option>
        <option id="col2o2">B</option>
        <option id="col2o3">C</option>
        <option id="col2o4">E</option>
      </select>
    </td>
    <td>
      <select class="col3">
        <option id="col3o1">A</option>
        <option id="col3o2">B</option>
        <option id="col3o3">C</option>
        <option id="col3o4">E</option>
      </select>
    </td>
  </tr>
  <br>
  <tr>
    <td><input type="checkbox" name="check1" />&nbsp;</td>
    <td>
      <select class="s1">
        <option id="s1o1">A</option>
        <option id="o2">B</option>
        <option id="o3">C</option>
        <option id="o4">E</option>
      </select>
    </td>
    <td>
      <select class="s2">
        <option id="s2o1">A</option>
        <option id="s2o2">B</option>
        <option id="s2o3">C</option>
        <option id="s2o4">E</option>
      </select>
    </td>
    <td>
      <select class="s3">
        <option id="s3o1">A</option>
        <option id="s3o2">B</option>
        <option id="s3o3">C</option>
        <option id="s3o4">E</option>
      </select>
    </td>
  </tr>
  <br>
  <tr>
    <td><input type="checkbox" name="check1" />&nbsp;</td>
    <td>
      <select class="s1">
        <option id="s1o1">A</option>
        <option id="o2">B</option>
        <option id="o3">C</option>
        <option id="o4">E</option>
      </select>
    </td>
    <td>
      <select class="s2">
        <option id="s2o1">A</option>
        <option id="s2o2">B</option>
        <option id="s2o3">C</option>
        <option id="s2o4">E</option>
      </select>
    </td>
    <td>
      <select class="s3">
        <option id="s3o1">A</option>
        <option id="s3o2">B</option>
        <option id="s3o3">C</option>
        <option id="s3o4">E</option>
      </select>
    </td>
  </tr>
</table>

Here's an even more simplified version, acting on the table rows

document.addEventListener(`click`, handle);

// create the table dynamically to keep demo lean
createTable();

function handle(evt) {
  if (evt.target.type === `checkbox`) {
    const selectedRow = evt.target.closest(`tr`);
    document.querySelectorAll(`tr`)
      .forEach( row => {
        // not selected
        if (row !== selectedRow) {
          row.querySelector(`[type=checkbox]`).checked = false;
          row.classList.remove(`selected`);
          return row.querySelectorAll(`select`)
            .forEach(s => s.setAttribute(`disabled`, true));
        }
        // selected
        row.classList[[`remove`, `add`][+evt.target.checked]](`selected`);
        row.querySelectorAll(`select`).forEach(s => 
          s[`${[`set`,`remove`][+evt.target.checked]}Attribute`](`disabled`, true));
      });
  }
}

function createTable() {
  const table = document.createElement(`table`);
  const repeat = (str, n) => Array(n + 1).join(str);
  const select = `<td><select>
      <option>A</option>
      <option>B</option>
      <option>C</option>
      <option>E</option></select></td>`;
  const row = `<tr>
    <td><input type="checkbox" /></td>
    ${repeat(select, 3)}</tr>`;
    
  table.insertAdjacentHTML(`beforeend`, repeat(row, 3));
  
  document.body.appendChild(table);
  // disable all selectors initially
  document.querySelectorAll(`td select`)
    .forEach(s => s.setAttribute(`disabled`, true));
}
body {
  margin: 2rem;
}

tr.selected {
  background-color: lightgreen;
}

tr td:nth-child(1) {
  padding-right: 6px;
}

Upvotes: 2

Naren Murali
Naren Murali

Reputation: 56099

This works great! uncheck all checkboxes except the one having current focus '.tbl [type="checkbox"]:not(:focus)' then manipulate the select boxes

$(document).ready(function(){
  $('.tbl [type="checkbox"]').on('click', function() {
    $('.tbl [type="checkbox"]:not(:focus)').prop('checked', false);
    $('.tbl select').attr('disabled', true);
    $(this).parent().parent().find('select').attr('disabled', !$(this).prop('checked'));
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="tbl">
<tr>
  <td><input type="checkbox" name="check1" class = "selectRow" />&nbsp;</td>
  <td>
   <select class="col1" disabled>
       <option id="col1o1">A</option>
       <option id="col1o2">B</option>
       <option id="col1o3">C</option>
       <option id="col1o4">E</option>
   </select>
  </td>
    <td>
   <select class="col2" disabled>
       <option id="col2o1">A</option>
       <option id="col2o2">B</option>
       <option id="col2o3">C</option>
       <option id="col2o4">E</option>
   </select>
  </td>
    <td>
   <select class="col3" disabled>
       <option id="col3o1">A</option>
       <option id="col3o2">B</option>
       <option id="col3o3">C</option>
       <option id="col3o4">E</option>
   </select>
  </td>
</tr>
<br>
<tr>
  <td><input type="checkbox" name="check1" />&nbsp;</td>
  <td>
   <select class="s1" disabled>
       <option id="s1o1">A</option>
       <option id="o2">B</option>
       <option id="o3">C</option>
       <option id="o4">E</option>
   </select>
  </td>
    <td>
   <select class="s2" disabled>
       <option id="s2o1">A</option>
       <option id="s2o2">B</option>
       <option id="s2o3">C</option>
       <option id="s2o4">E</option>
   </select>
  </td>
    <td>
   <select class="s3" disabled>
       <option id="s3o1">A</option>
       <option id="s3o2">B</option>
       <option id="s3o3">C</option>
       <option id="s3o4">E</option>
   </select>
  </td>
</tr>
<br>
<tr>
  <td><input type="checkbox" name="check1" />&nbsp;</td>
  <td>
   <select class="s1" disabled>
       <option id="s1o1">A</option>
       <option id="o2">B</option>
       <option id="o3">C</option>
       <option id="o4">E</option>
   </select>
  </td>
    <td>
   <select class="s2" disabled>
       <option id="s2o1">A</option>
       <option id="s2o2">B</option>
       <option id="s2o3">C</option>
       <option id="s2o4">E</option>
   </select>
  </td>
    <td>
   <select class="s3" disabled>
       <option id="s3o1">A</option>
       <option id="s3o2">B</option>
       <option id="s3o3">C</option>
       <option id="s3o4">E</option>
   </select>
  </td>
</tr>
</table>

Upvotes: 0

Rory McCrossan
Rory McCrossan

Reputation: 337560

The issue is because checkedRow holds a jQuery object. When you use that in an if condition it will always equate to true. You instead need to get the checked property from that element and use that in the condition instead.

Also note that the logic can be made much more succinct and extensible through the use of common selectors instead of incremental ones. In addition, you should look to add the disabled attribute to the HTML directly. Adding it via JS means that there will be a visible flash where the element is loaded as enabled, then when the DOM loads it will be disabled which is not good for your UX.

jQuery($ => {
  selectRow();
  $('.tbl').on('change', '.selectRow', selectRow);

  function selectRow() {
    $('.tbl tbody tr').each(function() {
      let $row = $(this);
      let $checkbox = $row.find('.selectRow');
      $row.find('select').prop('disabled', !$checkbox.prop('checked'));
    });
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="tbl">
  <tr>
    <td><input type="checkbox" name="check1" class="selectRow" />&nbsp;</td>
    <td>
      <select class="col1" disabled="disabled">
        <option id="col1o1">A</option>
        <option id="col1o2">B</option>
        <option id="col1o3">C</option>
        <option id="col1o4">E</option>
      </select>
    </td>
    <td>
      <select class="col2" disabled="disabled">
        <option id="col2o1">A</option>
        <option id="col2o2">B</option>
        <option id="col2o3">C</option>
        <option id="col2o4">E</option>
      </select>
    </td>
    <td>
      <select class="col3" disabled="disabled">
        <option id="col3o1">A</option>
        <option id="col3o2">B</option>
        <option id="col3o3">C</option>
        <option id="col3o4">E</option>
      </select>
    </td>
  </tr>
  <br>
  <tr>
    <td><input type="checkbox" name="check1" class="selectRow"  />&nbsp;</td>
    <td>
      <select class="s1">
        <option id="s1o1">A</option>
        <option id="o2">B</option>
        <option id="o3">C</option>
        <option id="o4">E</option>
      </select>
    </td>
    <td>
      <select class="s2">
        <option id="s2o1">A</option>
        <option id="s2o2">B</option>
        <option id="s2o3">C</option>
        <option id="s2o4">E</option>
      </select>
    </td>
    <td>
      <select class="s3">
        <option id="s3o1">A</option>
        <option id="s3o2">B</option>
        <option id="s3o3">C</option>
        <option id="s3o4">E</option>
      </select>
    </td>
  </tr>
  <br>
  <tr>
    <td><input type="checkbox" name="check1" class="selectRow"  />&nbsp;</td>
    <td>
      <select class="s1">
        <option id="s1o1">A</option>
        <option id="o2">B</option>
        <option id="o3">C</option>
        <option id="o4">E</option>
      </select>
    </td>
    <td>
      <select class="s2">
        <option id="s2o1">A</option>
        <option id="s2o2">B</option>
        <option id="s2o3">C</option>
        <option id="s2o4">E</option>
      </select>
    </td>
    <td>
      <select class="s3">
        <option id="s3o1">A</option>
        <option id="s3o2">B</option>
        <option id="s3o3">C</option>
        <option id="s3o4">E</option>
      </select>
    </td>
  </tr>
</table>

Upvotes: 0

Related Questions