skip to Main Content

I have a datatable with input fields. When a user inputs to a field, I need to find the row number they have input to. I asked a previous question, and got a good answer, but the answer stops working if the datatable is responsive, and the field is in the child popdown.
Here is my code:

function drawInput(data, type, row, meta) {
  return '<input id="r' + meta.row + 'c' + meta.col + '" val="' + data + '"></input>';
}
var data = [{
  c1: 'r1c1',
  c2: 'r1c2',
  c3: 'r1c3'
}, {
  c1: 'r2c1',
  c2: 'r2c2',
  c3: 'r2c3'
}];
$(function() {
  var table = $('table').dataTable({
    info: false,
    searching: false,
    ordering: false,
    paging: false,
    columns: [{
        defaultContent: '<span></span>'
      },
      {
        data: 'c1',
        name: 'c1',
        defaultContent: '<input></input>',
        render: drawInput
      },
      {
        data: 'c2',
        name: 'c2',
        defaultContent: '<input></input>',
        render: drawInput
      },
      {
        data: 'c3',
        name: 'c3',
        defaultContent: '<input></input>',
        render: drawInput
      }
    ]
  });
  table.api().rows.add(data);
  table.api().draw();
  $('body').on('change', 'table :input', function(e) {
    // Find the row that contains the input field
    //console.log(this);
    var row = table.api().row($(this).closest('td'));
    // Show the row index - result is undefined! Why?
    console.log(row.index());
  });
});
<link href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
<link href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.dataTables.min.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>

<div style='width:150px;'>
<table width="100%" class="responsive">
  <thead>
    <tr>
      <th></th>
      <th>Col 1</th>
      <th>Col 2</th>
      <th>Col 3</th>
    </tr>
  </thead>
  <tbody>
</table>
</div>

If you run this in a window large enough to fit the whole table in, it works fine. But if you narrow the window down, so that the right hand column responsively drops into a child row, the code to find the row index no longer works.

What is the correct incantation to find row for a child cell?

3

Answers


  1. When .row($(this).closest("td")).index() is undefined, use table.api().row(this).index().

    Strangely, table.api().row(this) only works on the expanded row, not the original, so need to continue to use .closest("td") for the original row.

    Specifically table.api().row(...) will return a jQuery object, so to check if any rows have been returned, check for .length === 0.

    Giving:

    let row = table.api().row($(this).closest("td"))
    if (row.length === 0) row = table.api().row(this);
    

    then .index() will give the expected row index.

    Updated snippet:

    function drawInput(data, type, row, meta) {
      return '<input id="r' + meta.row + 'c' + meta.col + '" val="' + data + '"></input>';
    }
    var data = [{
      c1: 'r1c1',
      c2: 'r1c2',
      c3: 'r1c3'
    }, {
      c1: 'r2c1',
      c2: 'r2c2',
      c3: 'r2c3'
    }];
    $(function() {
      var table = $('table').dataTable({
        info: false,
        searching: false,
        ordering: false,
        paging: false,
        columns: [{
            defaultContent: '<span></span>'
          },
          {
            data: 'c1',
            name: 'c1',
            defaultContent: '<input></input>',
            render: drawInput
          },
          {
            data: 'c2',
            name: 'c2',
            defaultContent: '<input></input>',
            render: drawInput
          },
          {
            data: 'c3',
            name: 'c3',
            defaultContent: '<input></input>',
            render: drawInput
          }
        ]
      });
      table.api().rows.add(data);
      table.api().draw();
      $('body').on('change', 'table :input', function(e) {
        // Find the row that contains the input field
        console.log(this.id, this.name, table.api().row($(this).closest("td")).index(), table.api().row(this).index());
        
        var row = table.api().row($(this).closest("td"))
        if (row.length === 0) row = table.api().row(this);
        // Show the row index - result is undefined! Why?
        console.log(row.index());
      });
    });
    <link href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
    <link href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.dataTables.min.css" rel="stylesheet" type="text/css" />
    <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
    <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
    <script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>
    
    <div style='width:150px;'>
    <table width="100%" class="responsive">
      <thead>
        <tr>
          <th></th>
          <th>Col 1</th>
          <th>Col 2</th>
          <th>Col 3</th>
        </tr>
      </thead>
      <tbody>
    </table>
    </div>
    Login or Signup to reply.
  2. https://datatables.net/reference/type/row-selector#Options says about passing a node as row selector,

    tr – table row element.
    td – table cell element (Since: 1.10.11).
    Any element which has a data-dt-row attribute assigned to it, or a parent (Since: 1.10.11). This can be used by extensions such as FixedColumns and Responsive to allow easy row selection.

    If you check the actual DOM, it looks like this:

    enter image description here

    So there is an element with a data-dt-row attribute, only it is not a td, it’s a li.

    So you need to find either that closest element with that data attribute, or if that does not exist, pick the closest td instead.

    function drawInput(data, type, row, meta) {
      return '<input id="r' + meta.row + 'c' + meta.col + '" val="' + data + '"></input>';
    }
    var data = [{
      c1: 'r1c1',
      c2: 'r1c2',
      c3: 'r1c3'
    }, {
      c1: 'r2c1',
      c2: 'r2c2',
      c3: 'r2c3'
    }];
    $(function() {
      var table = $('table').dataTable({
        info: false,
        searching: false,
        ordering: false,
        paging: false,
        columns: [{
            defaultContent: '<span></span>'
          },
          {
            data: 'c1',
            name: 'c1',
            defaultContent: '<input></input>',
            render: drawInput
          },
          {
            data: 'c2',
            name: 'c2',
            defaultContent: '<input></input>',
            render: drawInput
          },
          {
            data: 'c3',
            name: 'c3',
            defaultContent: '<input></input>',
            render: drawInput
          }
        ]
      });
      table.api().rows.add(data);
      table.api().draw();
      $('body').on('change', 'table :input', function(e) {
        // Find the row that contains the input field
        var row = table.api().row($(this).closest('[data-dt-row], td').get(0));
        // Show the row index - result is undefined! Why?
        console.log(row.index());
      });
    });
    <link href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
    <link href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.dataTables.min.css" rel="stylesheet" type="text/css" />
    <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
    <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
    <script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>
    
    <div style='width:150px;'>
    <table width="100%" class="responsive">
      <thead>
        <tr>
          <th></th>
          <th>Col 1</th>
          <th>Col 2</th>
          <th>Col 3</th>
        </tr>
      </thead>
      <tbody>
    </table>
    </div>
    Login or Signup to reply.
  3. Again 😉 Need to just specify how to access the Table Cell.

    function drawInput(data, type, row, meta) {
      return '<input id="r' + meta.row + 'c' + meta.col + '" val="' + data + '"></input>';
    }
    $(function() {
      var data = [{
        c1: 'r1c1',
        c2: 'r1c2',
        c3: 'r1c3'
      }, {
        c1: 'r2c1',
        c2: 'r2c2',
        c3: 'r2c3'
      }];
      var table = $('table').dataTable({
        info: false,
        searching: false,
        ordering: false,
        paging: false,
        columns: [{
            defaultContent: '<span></span>'
          },
          {
            data: 'c1',
            name: 'c1',
            defaultContent: '<input></input>',
            render: drawInput
          },
          {
            data: 'c2',
            name: 'c2',
            defaultContent: '<input></input>',
            render: drawInput
          },
          {
            data: 'c3',
            name: 'c3',
            defaultContent: '<input></input>',
            render: drawInput
          }
        ]
      });
      table.api().rows.add(data);
      table.api().draw();
      $('body').on('change', 'tbody td input', function(e) {
        console.log(table.api().cell(this.parentNode).index());
        console.log(table.api().row(this.parentNode).index());
      });
    });
    <link href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
    <link href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.dataTables.min.css" rel="stylesheet" type="text/css" />
    <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
    <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
    <script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>
    
    <div style='width:150px;'>
      <table width="100%" class="responsive">
        <thead>
          <tr>
            <th></th>
            <th>Col 1</th>
            <th>Col 2</th>
            <th>Col 3</th>
          </tr>
        </thead>
        <tbody>
      </table>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search