1

I'm having some difficulty migrating some Client Side Datatables logic to Server Side.

My current issue is that with Datatables, if you want to paginate a large set of data (20,000+ rows) I first need to load all the rows in the Controller and then pass them to the view:

$records = \App\Records::get();

return view("example.datatables")->with(["records" => $records]);

Following that, this takes about 2 minutes of waiting before everything is loaded and Datatables paginates the records into pages of 500:

$("#table").DataTable({
  paging: true,
  pageLength: 500,
  ...
});

I've changed the Datatables declaration to handle Server Side processing via ajax like so:

$("#table").DataTable({
  processing: true,
  serverSide: true,
  ajax: {
    url: "...",
    type: "GET"
  }, paging: true,
  pageLength: 500,
  ...
});

Getting this to work as I'd like has gone quite well, but the issue is that Datatables is overriding or ignoring what I'm sending back from my ajax request:

$columnData = [];
foreach($recordsFromDatabase AS $record){
  $columnDataObject = [];

  $columnDataObject[0] = '<td class="myClass" data-property="myProperty"><input type="text" name="customInput[]"/></td>'

  ...

  $columnData[] = $columnDataObject;
}

return response()->json([
  "draw" => (int)$request->input("draw"),
  "recordsTotal" => $totalRecords,
  "recordsFiltered" => $totalFilteredRecords,
  "data" => $columnData,
  "error" => null
]);

Basically, what I'm sending back is a json response containing data, which is an array of columns, which are <td> elements, instead of just a plain value. So <td>Value</td> vs Value.

Datatables gives the illusion that this is working correctly, but I end up with

<tr role="row" class="even">
  <td class="sorting_1"><input type="text" name="customInput[]"/></td>
  ...
</tr>
<tr role="row" class="odd">
  <td class="sorting_1"><input type="text" name="customInput[]"/></td>
  ...
</tr>

It renders the <input> inside of the <td> correctly, but class="myClass" data-property="myProperty" are missing, which destroys the extended functionality of my table.

Is there some way to tell Datatables that what I'm sending back are valid <td> elements, and all it needs to do is add an odd or even class? (and even then, that's just for styling I think).

4
  • Look up laravel pagination laravel.com/docs/5.4/pagination Commented Jul 21, 2017 at 18:10
  • This is not an issue with Laravel pagination, nor pagination in general really. Commented Jul 21, 2017 at 18:20
  • You do not need Datatables when you can do all of this with laravels pagination classes and doing it with pagination will sped up the process in general because youll be processing chunks of x instead of 20,000 Commented Jul 21, 2017 at 18:32
  • I know that, and believe me, I don't want to use Datatables for that very reason alone, but I am locked in due to client requirements. Also, it's a pretty niche issue, so even though Laravel Pagination would work wonders, it's not an option for me. Cheers on the suggestion though. Commented Jul 21, 2017 at 18:44

2 Answers 2

3

You're using jQuery DataTables incorrectly.

You should not send <td> elements as your data. Use columns.render option to produce content for your cell and/or columns.createdCell option to add attributed to <td> element.

For example:

$('#example').DataTable( {
  "columnDefs": [ {
    "targets": 3,
    "createdCell": function (td, cellData, rowData, row, col) {
      $(td)
        .attr('data-property', rowData['myCustomProperty'])
        .addClass(rowData['myClass']);
    }
  } ]
} );

For Laravel use excellent Laravel DataTables package to correctly display table in server-side processing mode.

Sign up to request clarification or add additional context in comments.

3 Comments

I figured I was using it wrong by sending html back, thanks for clearing that up. Only issue is these data-* attributes I need to send back have to be generated Server Side; what would be return data look like to handle that?
For example, on the first <td>, I need data-record-id="'.$record->id.'">...</td>, so it either needs to be a property on the Server Side, or somehow passed to JS via the response
@TimLewis, you can send IDs as part of your response. You don't have to assign data- attributes just to retrieve ID, full row data is available at any time using row().data() API method and you can pass tr element as an argument to row() function.
0

So I ended up still sending HTML via my response, and using datatable's createdRow callback, I was able to parse the HTML into local DOM elements, check their classes and attributes, and assign them to the row/column as required:

createdRow: function(row, data, rowIndex) {
  $.each($("td", row), function (colIndex) {
    var elementFromData = $.parseHTML(data[colIndex]);
    var element = elementFromData[0];

    var elementClass = $(element).attr("class");
    if(typeof elementClass !== undefined){
      $(this).addClass(elementClass);
    }

    var attributes = [
      {
        label: "data-id",
        value: $(element).attr("data-id")
      }, ...
    ];

    for(var i = 0; i < attributes.length; i++){
      var attribute = attributes[i];

      if(typeof attribute.value !== undefined){
        $(this).attr(attribute.label, attribute.value);
      }
    }
  });
}, ...

It may not be the prettiest solution, and I understand that returning HTML from my AJAX request is inefficient, but due to time constraints this was the best solution I could come up with.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.