15

I am using jQuery Datatables plugin for a smal table (12 rows). Some <input type="text" ... fields allow editing. When the input field loses focus I need to validate its value and possibly change the field value. I haven't been able to get modified input field values to be recognized by DataTables without issuing a .draw() afterwards, but this causes the table to scroll to the top of the table.

Is there a way of maintaining the current scroll position after issuing a .draw()?

$('#mytable').on('blur', 'input', function (e) {

    var inputFieldId = this.id;
    var inputFieldVal = $(this).val();

    { ... perform validation of field value ... }

    $('#mytable').DataTable().rows().invalidate().draw();
});

EDIT

I saw someone trying to do the same thing I am and they indicated that the following code worked for them. This seems like a very simple way of accomplishing what I need, but I'm always getting scrollTop = 0 myself. Anyone see how I can get the row index of the currently selected row?

var scrollPos = $(".dataTables_scrollBody").scrollTop();
$('#mytable').DataTable().rows().invalidate().draw(false);
$(".dataTables_scrollBody").scrollTop(scrollPos);
rwkiii
  • 5,716
  • 18
  • 65
  • 114
  • 1
    Sorry I didn't see your changes, you code is correct, but try with scrollTo() $(".dataTables_scrollBody").scrollTo('#IDROW'). which 'IDROW' is the ID of the ROW or just ID of the input you changed – JC Sama Dec 27 '14 at 13:39
  • Just in case you have multiple dataTables with the same className, you should use ID selector $("#divContrainer1 > .dataTables_scrollBody").scrollTop() – JC Sama Dec 27 '14 at 13:43
  • Yes, you can do that. With a dirty hack, but you can. Seek for my answer below. – PatlaDJ Jun 19 '17 at 21:59

7 Answers7

26
var table = $('table#example').DataTable({
    "preDrawCallback": function (settings) {
        pageScrollPos = $('div.dataTables_scrollBody').scrollTop();
    },
    "drawCallback": function (settings) {
        $('div.dataTables_scrollBody').scrollTop(pageScrollPos);
    }
});

This appears to work for me. I just had to find the div.dataTables_scrollBody after the table was drawn.

ChesuCR
  • 9,352
  • 5
  • 51
  • 114
Paul Matthew
  • 361
  • 3
  • 2
  • Correct answer. – Tomasz Majerski Dec 06 '16 at 07:27
  • saved my time. Thank you – Naila Akbar Jan 02 '17 at 12:57
  • I think this is a better answer. Works great for me. It's a simple plug-and-play and you're done. It would be safer though if you add the table ID before selecting the scrollbody. `$('table#example div.dataTables_scrollBody').scrollTop();` – thisjt Jul 28 '20 at 15:02
  • I found that when I use a sticky header sometimes I get another table header added to the top of the page. If I wrap the `drawCallback` in `setTimeout` and set it to to a small interval it avoids it. `tableConfig.drawCallback = () => setTimeout(() => $('div.dataTables_scrollBody').scrollTop(pageScrollPos);, 50);` – Ryan Jan 21 '22 at 15:17
7

Just wanted to add this here though it's a slightly different scenario - It worked for my case and will likely be useful to some others who arrive here looking for answers.

I'm using server side processing and doing a refresh of table data once every 10 seconds with table.ajax.reload(). This function does accept an argument to maintain current paging value but fails to keep scroll position. The solution was very similar to the one the OP mentioned and sets the scroll position on the callback. Not sure why it didn't work for him but here's the interval code I'm using with success:

setInterval( function () {
    scrollPos = $(".dataTables_scrollBody").scrollTop();
    myTable.ajax.reload(function() {
        $(".dataTables_scrollBody").scrollTop(scrollPos);
    },false);
}, 10000 );
7

If you pass the draw function the page parameter, the table will not shift in scrolling, but it will re-read from the .DataTable source. E.g. after "saving" data that updates the DataTable:

$("your-selector").DataTable().row(t_itemid).invalidate();
$("your-selector").DataTable().row(t_itemid).draw('page');

Note: I am making use of an id column in my DataTable instantiation which makes it easy to work directly with a single row. But I believe the page parameter will give the desired result.

Adeel
  • 2,901
  • 7
  • 24
  • 34
Charlie
  • 115
  • 2
  • 9
  • 4
    ```$table.draw('page')``` works better than any of the other solutions. Setting scrollTop directly will scroll, but will also make the datatable object lose track of where it is and other controls will misreport data such as the start/end rows being displayed etc – mwag Mar 21 '19 at 05:39
  • Worked perfect for me. – Rob Breidecker Aug 27 '19 at 19:15
5

The way I solved it with DataTables 1.10 is to use preDrawCallBack to save the ScrollTop position and then DrawCallback to set it.

var pageScrollPos = 0;

var table = $('#example').DataTable({
  "preDrawCallback": function (settings) {
    pageScrollPos = $('body').scrollTop();
  },
  "drawCallback": function (settings) {
    $('body').scrollTop(pageScrollPos);
  }
});
sur
  • 580
  • 8
  • 14
3

I don't think you can do that, but you can use the Callback function instead:

$(document).ready(function() {
    var selected = [];

    $("#example").dataTable({
        "processing": true,
        "serverSide": true,
        "ajax": "scripts/ids-arrays.php",
        "rowCallback": function( row, data ) {
            if ( $.inArray(data.DT_RowId, selected) !== -1 ) {
                $(row).addClass('selected');
            }
        }
    });

    $('#example tbody').on('click', 'tr', function () {
        var id = this.id;
        var index = $.inArray(id, selected);

        if ( index === -1 ) {
            selected.push( id );
        } else {
            selected.splice( index, 1 );
        }

        $(this).toggleClass('selected');
    } );
} );

Ref : https://datatables.net/examples/server_side/select_rows.html

JC Sama
  • 2,214
  • 1
  • 13
  • 13
  • Thank you. I edited my post with a solution someone said worked for them, but scrollTop for me is always equal to 0. Do you see any merit in the edited example? I guess I need to set scrollTop to the currently selected row index, but given my event trigger I am not sure how to get the current row index. I haven't tried your example yet because I don't completely understand how it works. – rwkiii Dec 27 '14 at 02:59
  • you can add and ID attribute for one of your row element, and then yous $('body').scrollTo('#target'); after editing your element. if my explanation is not clear enough let me know. – JC Sama Dec 27 '14 at 13:16
0

How about this hack? It does not involve scrollTop() First open jquery.dataTables.js and seek for this line, and remove it:

divBodyEl.scrollTop = 0

After that put the following code before your draw()/clear() invocations:

var $tbl=$('#my_table_id');
if (!document.getElementById('twrapper')) $tbl.wrap( '<div id="twrapper" style="display:block; height:'+$tbl.height()+'px;"></div>' );
else $('#twrapper').css('height',$tbl.height()+'px');

It took me some time to figure out this.

PatlaDJ
  • 1,226
  • 2
  • 17
  • 31
0

The following code retains the scroll position upon Datatables server side reload.

var table =  $('#mytable').DataTable();

var start_row = table.scroller.page()['start'];

table.ajax.reload(function () {

    table.scroller().scrollToRow(start_row, false);

}, false);