Loaded State Is NOT Overwriting The Current DOM DataTables State

Loaded State Is NOT Overwriting The Current DOM DataTables State

marklmarkl Posts: 9Questions: 2Answers: 0
edited December 2014 in Free community support

I have a JQuery Datatables application that I’m trying to load the state from a database with a button click. During the button click event, I retrieve the desired state (oData) from one database table (tblSavedStates), and then I overwrite the state (oData) value in another database table (tblState) which holds the saved state of my web page. Next, I reload the web page and the “stateLoadCallback” function retrieves the new saved state (oData) value from the database. However, I cannot get the “stateSaveCallback” function to save the correct state (the one returned by the “stateLoadCallback” function) into the database. It just saves the current state of the DOM object and not the retrieved state. I’m currently using version 1.10.1 and here’s a snippet of my JQuery code:

// Initialization
    var oTable = $('#mytable').dataTable({
    "dom": 'RC<"clear">lfrtip',
    "processing": true,
    "serverSide": true,
    "ajax": baseurl + "MyController/IndexAjaxHandler?someId=" + someId,
    "sServerMethod": "POST",
    "stateSave": true,
"stateSaveCallback": function (oSettings, oData) {
            /* Save the oData in the database */
            $.ajax({
                type: 'POST',
                data: { url: $(location).attr('href'), oData: JSON.stringify(oData)},
                dataType: "json",
                async: false,
                url: baseurl + 'MyController/SaveOData',
                success: function (data) {
                },
                error: function () {
                }
            });
        },
        "stateLoadCallback": function (oSettings) {
            /* Get the oData from the database */
            var oData;
            $.ajax({
                type: 'POST',
                async: false,
                data: { url: $(location).attr('href') },
                url: baseurl + 'MyController /GetOData',
                success: function (data) {
                    oData = data.oData;
                },
                error: function () {
                }
            });

            /* If returned oData is not an empty string, then parse it */
            if (oData != '') {
                return JSON.parse(oData);
            }
        },

This question has an accepted answers - jump to answer

Answers

  • marklmarkl Posts: 9Questions: 2Answers: 0

    Update - After some searching, I found a post that mimics my issue and how the returned state is being ignored.

    http://datatables.net/forums/discussion/21894/problems-with-statesavecallback-and-stateloadcallback#

    Any help would be greatly appreciated.

  • allanallan Posts: 63,531Questions: 1Answers: 10,474 Site admin

    Looks like it should work. Can you link to the page in question so I can debug it please?

    Thanks,
    Allan

  • marklmarkl Posts: 9Questions: 2Answers: 0
    edited December 2014

    Thank you Allan for taking the time to assist me. I cannot post a link to my code but I'll try my best to describe the situation.

    I'm loading the saved state from the database with a button click and it's returning the correct state during the “stateLoadCallback” function. However, during the “stateSaveCallback” function it's not overwriting the DOM state. After further review, I discovered that the search, sort and paging is working as expected but the column visibility in the returned state is not being honored. Here's some additional code:

            "initComplete": function (oSettings, json) {
                /* Update the column visibility status of the checboxes in the external form */
                $.each(oSettings.aoColumns, function (iCol) {
                    if (iCol != 0 || iCol != 1) {  //Exclude the first column and the second column
                        if (oSettings.aoColumns[iCol].bVisible == false) {
                            var nCol = getColumnName(iCol);
                            $('input[data-datatables-col-name="' + nCol + '"]').removeAttr('checked');
                        }
                    }
                });
            },
    "fnServerParams": function (aoData) {
                // Retrieve the searchCriteria array of objects from the database
                $.ajax({
                    type: "POST",
                    async: false,
                    url: baseurl + 'MyController/GetSearchCriteria' + '?url=' + $(location).attr('href'),
                    success: function (data) {
    
                        // if returned oData is not an empty string, then parse it
                        if (data != '') {
                            searchCriteria = JSON.parse(data);
                        }
    
                        // If the retrieved searchCriteria array of objects is null then set it to an empty array 
                        if (searchCriteria == null) {
                            searchCriteria = [];
                        }
    
                        // Iterate thru the searchCriteria array of objects
                        var i;
                        for (i = 0; i < searchCriteria.length; i++) {
    
                            // Set the corresponding searchContainer input value on DOM with the searchCriteria object
                            $('#' + searchCriteria[i].name).val(searchCriteria[i].value);
    
                            // Pushing each name/value pair that was found from the searchButton click event into the aoData array
                            // which will be sent to the server in the request
                            aoData.push(searchCriteria[i]);
                        }          
                    },
                    error: function (data) {
                        // do something
                    }
                });
            }
    

    Also, here's the order of events after the button click event:

    1) "stateLoadCallback" event
    2) "fnServerParams" event
    3) "stateSaveCallback" event
    4) "initComplete" event

  • allanallan Posts: 63,531Questions: 1Answers: 10,474 Site admin

    I'm loading the saved state from the database with a button click

    Is this after the DataTable has initialised? The state can only be loaded during initialisation. There isn't an API method at the moment to restore a state once the table has been constructed.

    After further review, I discovered that the search, sort and paging is working as expected but the column visibility in the returned state is not being honored

    So the state is loading (in which case you can ignore my above comment), and only the column visibility is being ignored? Are you using Responsive perhaps? I'm afraid I'm really only guessing without being able to see the problem.

    Allan

  • marklmarkl Posts: 9Questions: 2Answers: 0
    edited December 2014

    I'm not using Responsive. During the button click event, the database is replacing the saved state and then I reload the page. So, the table is initialised one time. During the "stateLoadCallback" event, the returned state has the correct column visibility value for each column but they're not being applied to the DOM object. How can I accomplish this task?

  • allanallan Posts: 63,531Questions: 1Answers: 10,474 Site admin

    State saving should take the column visibility into account - I've just put together a little example together showing this.

    To see it in action, use ColVis to hide the "Name" column and then click the "Run with JS" button which is basically a reload. The "Name" column will still be hidden.

    I'm afraid I would need a test page showing the issue to be able to help much more than that as i don't know what is going wrong.

    Allan

  • marklmarkl Posts: 9Questions: 2Answers: 0

    I'll try to recreate a scaled down version of my application in a JS Bin test page.

  • marklmarkl Posts: 9Questions: 2Answers: 0
    edited December 2014

    @allan

    Update - After hours of debugging, I finally identified the issue. When I saved the state (oData) into the database, a timestamp, the "time" value, would be created at that time. Well, the "_fnLoadState" function in the API has a code check to reject old data (state) if the iStateDuration is greater than zero and the state.time (retrieved "time" value") is less than the current datetime minus the iStateDuration multiplied by one thousand. Here's the code check:


    /* Reject old data */ var duration = settings.iStateDuration; if ( duration > 0 && state.time < +new Date() - (duration*1000) ) { return; }

    To test my theory, I edited the timestamp value of my saved state in the database table and voila!, it worked.

    So, what's the best way to handle this issue? Should I overwrite the timestamp values of my saved states to a value of "9999999999999" when I save them into the database or do you have a better workaround?

  • allanallan Posts: 63,531Questions: 1Answers: 10,474 Site admin

    So just to check - DataTables is throwing away the data because it is stale? You could use stateDuration to have a longer state duration if you want - set it to a year perhaps. Or 100 years if needed.

    The alternative is to override the state data which you could also do.

    Allan

  • marklmarkl Posts: 9Questions: 2Answers: 0

    Yes. The "_fnLoadState" function is throwing away the data because it's stale but in my case it's not stale.

  • allanallan Posts: 63,531Questions: 1Answers: 10,474 Site admin
    Answer ✓

    In which case, is the stateDuration option the correct one to use? If you want to change the duration for which the data is valid for, then I think that would be the best way of doing it as that is what it is designed for.

    Allan

This discussion has been closed.