How do I make DataTables redraw a server-side table and maintain the current search and page length?

How do I make DataTables redraw a server-side table and maintain the current search and page length?

amnesthesiaamnesthesia Posts: 4Questions: 1Answers: 0
edited November 2015 in Free community support

Hiya!

I'm currently using datatables to display large resultsets from an API. We perform actions on this resultset, causing some rows to be removed, after which I want to redraw the table -- basically, rows are selected, and a PUT request is performed updating a relationship in the API and causing them to no longer be part of the result set from the API.

I have previously solved this by doing:

$("#load-data-table table").DataTable().ajax.url($("#load-data-table table").DataTable().ajax.url()+"&length="+$("select[name='ajax-table_length']").val())
$("#load-data-table table").DataTable().ajax.reload()

If a user has searched for anything and a subset of the resultset is displayed, which correctly refreshes the table (but does not send the correct parameters to the API again, it only reloads from the same URL without passing all the column[0][... parameters). It also breaks a lot of other stuff, like searching afterwards, and it doesn't maintain the search value either.

To do this, I've instead tried to replace this code with

$("#load-data-table table").DataTable().search($("input[type=search]").val()).draw();

And ... This works fine if I try it in a console. But as soon as I've removed any rows from the table, it breaks: Basically, it stops doing anything but just reloads the default URL without maintaining search parameters, nor sending the datatable column parameters to the server.

The main problem I seem to be having is that the column, search and length parameters are not sent again when the ajax is reloaded, which means the wrong data is returned and the displayed table is not correct, and it happens both when using the .search function to just re-search for the value, and when using the ajax.reload method..

How can I make it reload ajax (WITH all the same columns, length and search parameters) and then redraw the table?

Best regards,
Amnesthesia

Answers

  • jLinuxjLinux Posts: 981Questions: 73Answers: 75

    The draw() takes params that can prevent the table from doing that, so try table.search(table.search()).draw(false) i believe. Im on my cell now, ill double check later

  • amnesthesiaamnesthesia Posts: 4Questions: 1Answers: 0

    Thank you jLinux, but .. I get the same result from this though. An AJAX query is sent without the column[0][..., length and search parameters and the default resultset without any paging is returned (since there's no length parameter being sent) :(

  • allanallan Posts: 48,464Questions: 1Answers: 7,020 Site admin

    If you are using server-side processing (serverSide), just use draw() - reload.ajax() isn't particularly useful with server-side processing.

    If that doesn't work for you, we'd need a link to a test case showing the issue.

    Allan

  • amnesthesiaamnesthesia Posts: 4Questions: 1Answers: 0
    edited November 2015

    It's an internal system working with an internal API so I can't really provide a test case I'm afraid :( I really wish I could..

    Basically, I'll try to explain as best as I can what's happening:

    1. Create a map of columns and whether they are searchable, orderable, and which JSON variable name they have
    2. Set up a datatable with our given parameters and our endpoint URL
    3. Make a rowCallback that sets an ID attribute on each row
    4. Make table rows clickable to be able to set them to be selected, and push their ID into an array
    5. When clicking the Apply button, collect these IDs and iterate through them.
    6. For each iteration, create a PUT request with a bunch of other IDs to be sent to the API to assign a relationship
    7. Remove the table row
    8. After all PUT requests are sent, and the array with selected row IDs is empty, get new data from the API where these items are excluded and redraw the table, so that the table again contains one full page of rows again. This is the part that doesn't work, since the .draw(false) doesnt pass the same parameters to the API after removing a row...
    // Set up a datatable with default settings but allow overriding them with the `settings.datatable` variable
    // The settings variable contain our own settings, some of which we use to set up the datatable
    
    var t = $("#load-data-table table").dataTable($.extend({
                // If the page was loaded with any GET-parameters, also pass them along to the API together with any other parameters
                "ajax": { url: settings.api_url + settings.endpoint + (settings.endpoint.indexOf("?") > -1 ? "" : "?") + get_url_parameters(), dataSrc: "results" },
                   
                // Use serverside processing
                "serverSide": true,
    
                // Load the prepopulated columns map, mapping JSON variables, & whether orderable & searchable
                "columns": settings.columns,
    
                // Defaults to true
                "paging": true,
                "info": true,
    
                // Allow searching by default
                "searching": true,
    
                 // Display the Processing... text
                "processing": true,
                 
                "language": {
                    // Replace the Processing... text with an AJAX-loader
                    "processing": "<div class='table-loading'><img src='/assets/images/ajax-loader.gif' /></div>",
    
                    // Change the Pagination button labels
                    "paginate": {
                        "first": "<",
                        "last": ">",
                        "previous": "<",
                        "next": ">",
                        "search": "Filter"
                    }
                },
    
                // Set the ID of each row to be the ID of the JSON object
                "rowCallback": function(nRow, data, iDisplayIndex, iDisplayIndexFull){
    
    
                    // If this ID is in the list of currently selected rows make sure to set the .selected class on this tr
                    if($.inArray(""+data[settings.json_row_id], selected_rows) > -1)
                    {
                       // Add .tagged class to the row
                       $(nRow).addClass('tagged');
    
                        // Find the value in the third cell, and wrap it in a div to indicate that this value has been selected/tagged
                       $(nRow).find("td:nth-child(3)").html("<div class='tagged'>"+$(nRow).find("td:nth-child(3)").html() + "</div>");
                    }
                    // Set the row ID from the field defind in settings.json_row_id (which can be object.child.id, or just object.id, etc -- thats why we use split and reduce. This works fine.
                    $(nRow).attr("data-id", settings.json_row_id.split('.').reduce(index, data));
                 // Allow overriding our settings
                 }, settings.datatable));
    
    

    Each row is then clickable, and will be added to selected_rows when selected, and when Apply is clicked it will trigger a PUT-request for each row which causes a query to the API where the ID from this row, the elements ID, is assigned to a relationship in the API and thus will not be shown in the table. The rows are removed after the PUT request is sent, and the table is redrawn after the last PUT requests has finished and the selected_rows array is empty again.

    This code is as follows:

    $("#load-data-table").on("click", "tr", function(){ 
         $(this).toggleClass("selected");
         
         if(!$.inArray($(this).attr('data-id'), selected_rows))
                    {
                        selected_rows.push($(this).attr('data-id'));
                    }
    });
    
    $("#apply-button").click(function(){
     
                // Now take the labels_to_assign_rows_to variable (the IDs) and PUT them to the endpoint
    
                // First make sure all the IDs that are in the currently selected rows are actually in our array of selected IDs to send
                $("tr.selected").each(function(){
                    
                    if(!$.inArray($(this).attr('data-id'), selected_rows))
                    {
                        selected_rows.push($(this).attr('data-id'));
                    }
                });
    
    
                // For each of these selected row IDs
                $.each(selected_rows, function(i, row_id){
    
                    // Set up the parameters to send to update this object in the API
                    var parameters_to_send = {};
    
                    // Set up the data, where settings.field is the field to PUT as, i.e the parameter name, and its value
                    // is the primary key of that field. For example { object: primary_key }
                    parameters_to_send[settings.field] = []
    
                    // Populate the array with the IDs to send
                    $.each(labels_to_assign_rows_to, function(i, selected_label){
    
                        parameters_to_send[settings.field].push(selected_label);
                    });
    
                    // Set up the AJAX request
                    $.ajaxSetup({contentType: 'application/json', processData: false});
    
                    // Now PUT it to the API with our parameters (we make 1 PUT per row, to update different objects)
                    $.ajax({
                            url: settings.api_url + settings.endpoint + row_id,
                            type: 'PUT',
                            dataType: "json",
                            data: JSON.stringify(parameters_to_send),
                            cache: false
                    }).success(function(){
                            
                            // If the PUT request was successful, then find all the rows we just updated and remove them, and 1 by 1 remove them from the array
    
                            // It makes no difference which of these I use, it seems
                            $(".tagged-row[data-row-id="+row_id+"]").fadeOut().remove();   
                            //$("#load-data-table table").DataTable().rows($(".tagged-row[data-row-id="+row_id+"]")).remove()
    
                            // Find the rows ID in the array and remove it
                            selected_rows.splice($.inArray(row_id, selected_rows), 1);
                        });
    
                    // If this was the last call, then run the callback (we must do it like this to wait for the LAST async call to finish)
                    if(selected_rows.length < 1)
                        $("#load-data-table table").draw(false); 
                });
            })
    });
    
    

    The problem is that whenever I call .draw() it does redraw the table but it does not send the parameters with which columns are searchable, orderable, etc, what search parameter was used, or the length value. It makes a new API call with the URL set up in the AJAX settings, and no more parameters. This causes the wrong results to be returned, search isnt maintained, and neither is length.

  • allanallan Posts: 48,464Questions: 1Answers: 7,020 Site admin

    I'm afraid that without having a page that I can debug, there isn't a use amount of help that I can offer. As you can see in my examples if you call the draw() function it will sent the parameters every time.

    This is the first case I've heard of where the parameters are not being sent, which I why I would need to be able to debug the page.

    Allan

  • amnesthesiaamnesthesia Posts: 4Questions: 1Answers: 0
    edited November 2015

    I have resolved this problem and, in case anyone else runs into this, it's caused by line 41 in the second code sample I gave above.

    After setting $.ajaxSetup({ processData: false }); this causes dataTables to send [object Object] instead of parameterizing the parameters it should be sending ...

    Woooops. :)

    Thanks for your great work, support and quick response though Allan!

This discussion has been closed.