Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you programatically open multiple rows in DataTables

I thought this question would have been answered but I can't work this out. Have tried:

  • https://datatables.net/forums/discussion/25833/is-there-any-way-to-programmatically-select-rows
  • https://datatables.net/reference/api/row().select()

I'm using DataTables 1.10.16 in serverSide mode - my data is loaded in via ajax as opposed to being there on page load.

My markup is simply a table with an ID, #substancesTable:

<table id="substancesTable" cellspacing="0" width="100%">
    <thead>
        <tr>
            <th>ID</th>
            <th>EC</th>
            <th>CAS</th>
            <th>Name</th>
         </tr>
     </thead>
</table>

The js to load the data is as follows:

var substancesTable = $('#substancesTable').DataTable({
    "processing": true,
    "serverSide": true,
    "searching": false,
    "ajax": {
        "url": "/get-substances.json",
        "dataSrc": function (json) {
             return json.data;
        }
    }
});

This populates my table fine. I have an event handler such that when a user manually clicks on on a row (any <td> element inside the #substancesTable) it makes a further ajax request to obtain more data which is then populated inside the <td> that the user clicked. This code is also responsible for closing/collapsing any open rows:

$('#substancesTable tbody').on('click', 'td', function () {
    var tr = $(this).closest('tr');
    var row = substancesTable.row( tr );

    if ( row.child.isShown() ) {
        row.child.hide();
        tr.removeClass('shown');
    }
    else {
        row.child( expand_substance(row.data()) ).show();
        tr.addClass('shown');
    }
} );

The code above calls a function expand_substance which handles the ajax request mentioned. This all works fine.

What I'm trying to do is find a way to programatically open certain rows. What I mean by this is having an array of row ID's that the user has clicked on, e.g.

var openRows = [5, 6, 8, 33, 100];

This array data will be stored in Redis (cache) so if the user navigates away from the page, when they return, the data in openRows will be loaded and I want to open the appropriate rows. But I don't know how to tell DataTables to open rows 5, 6, 8, 33, 100, etc.

The links above don't seem to work for me. For example, if I try:

substancesTable.row(':eq(0)', { page: 'current' }).select();

I get a console error:

VM308:1 Uncaught TypeError: substancesTable.row is not a function

I'm not sure if that's even how to open the row but couldn't find any more information that helped.

So, is it possible to use JavaScript to open certain rows of the table based on an array of known ID's (openRows)?

like image 763
Andy Avatar asked Oct 31 '18 09:10

Andy


1 Answers

That one was fun to resolve (hoping I did)... since it is quite complicated and tricky.

First, I have to mention that it's not possible (or at least a pain) to build a demo using the server side feature, so I used DataTable's "zero configuration" example.

Now, I hope I correctly understand that a row index array is to be previously stored from user row clicks... And that it's the starting point of the current question to reuse that array to manipulate the rows.

In my example, there are only 57 rows... So I used this array: var targets = [5, 6, 8, 33].

The solution step by step:

  1. Use the drawCallback to run a for loop on the array.
  2. Get the drawn rows in the right order... Which means after sort.
    We need to use the row-selector along with the useful { order: 'applied' } trick.
    (Found in a dataTables forum question)
  3. Get the nodes from it.
  4. Target the right rows, based on the array, using the jQuery .eq() method.
    So we have to create a jQuery object with the row collection first (wrap with $()).
  5. Manipulate the rows!
    In my example, I just added a red background color to the child td.
    You will do your things from here.

So here is the whole function:

"drawCallback": function(){
  var api = this.api();

  for(i=0;i<targets.length;i++){
    $(api.rows({ order: 'applied' }).nodes()).eq(targets[i]).find("td").addClass("red");
    console.log(targets[i]);
  }
}

CodePen


Remember that rows are zero-based...
Notice that the row indexes manipulated above are after sort (so it reflects the order as currently displayed to user, not the order as supplied to Datatables from the markup or from Ajax.) That means the sorting shall be the same as when the user clicked the rows (thus saved the indexes). That may be a problem... ;)
like image 89
Louys Patrice Bessette Avatar answered Sep 29 '22 07:09

Louys Patrice Bessette