Andy
Andy

Reputation: 5395

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:

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)?

Upvotes: 7

Views: 1759

Answers (2)

Andy
Andy

Reputation: 5395

The answer to this was provided by a colleague and makes use of the rowCallback (https://datatables.net/reference/option/rowCallback) callback which DataTables provides.

var substancesTable = $('#substancesTable').DataTable({

// ...

"rowCallback": function(row) {
       var id = $(row).find('td:first').text();
       var index = $.inArray(id, openRows);

       if (index !== -1) {
           var tr = $(row).closest('tr');
           var row = substancesTable.row( tr );
           row.child( expand_substance(row.data()) ).show();
           tr.addClass('active');
       }
    }
});

This callback will post process each row (represented by row). The line var index = $.inArray(id, openRows); means is the current row (identified by the text from var id) in the array of openRows. Since the first column in my table contains the ID that's how we can get a match between var id and openRows.

If the ID is found it will then trigger a function I've written called expand_substance(). This is nothing to do with DataTables, it's a custom js function.

In my case the expand_substance() function is responsible for doing an ajax call to obtain some more details which are then populated into the row:

function expand_substance ( rowData ) {
    var div = $('<div/>')
        .text('Loading...');

    $.ajax( {
        url: '/view-substance/expand-substance/' + rowData.id,

        dataType: 'html',
        success: function ( data ) {
            div.html(data);
        }
    });

    return div;
}

This is only required because when the user expands a row in my application the details which are shown are obtained via an ajax request. In theory expand_substance() might not be used if the data was there on page load.

This works in my application. The other Answer provided to this post is along the right lines but does not use ajax source data, and it does not expand a row, but instead just highlights it in red. Therefore I've provided my own answer because this fully addresses the question and others may find it useful.

Upvotes: 0

Louys Patrice Bessette
Louys Patrice Bessette

Reputation: 33933

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... ;)

Upvotes: 1

Related Questions