Cannot get StateRestore to work on page refresh using AJAX

Cannot get StateRestore to work on page refresh using AJAX

PaulVickeryPaulVickery Posts: 14Questions: 3Answers: 0

I am sorry if this has been answered already somewhere, but I cannot find a solution. At the moment I am trying to get the basic ajax example to work for me as described at https://datatables.net/extensions/staterestore/examples/initialisation/ajax.html

Using the relevant php files from https://github.com/DataTables/StateRestore/tree/master/examples/data I can successfully recreate the example.

The problem that I have (and it is the same as the example ) is that when you save a state it works until you refresh the page and then the state "resets". The pull down menu still shows the state exists, but is doesn't do anything.

To replicate on the example (assuming there are no existing states)

  1. Refresh page
  2. Create a state (State 1)
  3. Click on ID to reverse the ID order
  4. Create a state (State 2)
  5. Using the "Save States" pull down menu, confirm that by selecting the individual states that they work correctly (which they do).
  6. Refresh the page
  7. Using the "Save States" pull down menu and select "State 2". It no longer works as the ID column is not reversed.

For completeness I have added the response below that I get from my server.

Any help would be appreciated, thank you.

Replies

  • allanallan Posts: 65,056Questions: 1Answers: 10,772 Site admin

    Yup, I see it too. Apologies for the error, I'm looking into it.

    Allan

  • allanallan Posts: 65,056Questions: 1Answers: 10,772 Site admin

    It is due to the ordering index (and other numbers) being stored as strings rather than numbers. DataTables has had enhancements that cause the restore not to work in this case (since it is a string, it can't find a column with that name).

    I think I need to modify StateRestore to convert back to numbers where they should be. I don't like this - it should have been sent as a JSON object to the server, not HTTP parameters, so that type could be retained. That is something for StateRestore 2...

    I'll post back later when I've had a chance to do this.

    Allan

  • PaulVickeryPaulVickery Posts: 14Questions: 3Answers: 0

    Hi Alan, thank you for your reply. As a newbie to this, I apologise if this is a silly idea, but if you don't want to change StateRestore at this stage, could the data not be manipulated in the PHP script?

  • allanallan Posts: 65,056Questions: 1Answers: 10,772 Site admin

    Hi Paul,

    I've just committed this change to address the porblem found here. It will be in the nightly build shortly.

    I've also committed this change to DataTables core, due to an error I saw while looking into this.

    You are right, the issue could be fixed in the PHP script, but since the Javascript sends HTTP parameters which are typeless, I don't think it would be right to expect the server to know to send back a specific type for certain properties.

    Regards,
    Allan

  • PaulVickeryPaulVickery Posts: 14Questions: 3Answers: 0

    Hi Alan

    Thank you for looking at this. Now that It is working, I have found a few other issues. I am not sure whether they are supported or not, but I have listed them anyway.

    I am not sure how to add a test case onto the Datatables https://live.datatables.net site with PHP files so I have temporarily loaded a test scenario at https://dt.taskmgr.co.uk for you to look at. Not sure why but the link keeps taking you to "https://dt.taskmgr.co.uk/defaultsite", so just remove the "/defaultsite" on the browser and you should see it.

    I have used the two php files and the 2500.txt file from Github. The other two files are listed below.

    Issues

    1. Colvis: State not remembered after refresh
    2. colReorder: State not remembered after refresh

    Quirks

    • Individual column search and the global search both are working, but with some quirks.
      Individual column search: A state is remembered after refresh, however the filter text is not displayed even though the filter is working. (I realise that this is how it has always been as I have seen comments on the forum about it). It is possible to remove the filter by selecting the appropriate footer box where the filter is and backspacing to delete the filter. (This obviously doesn’t change the “definition” of the state and the filter will be applied when the state is reselected.)
    1. Assuming no states created:
    2. Type Arm in the “First Name” footer and select Create State (State 1)
    3. Refresh Page
    4. Select State 1 from “ Saved States” (filter is correctly applied)
    5. Select “First Name” footer and Backspace. Filter is removed.
    6. Select State 1 from “ Saved States” (filter is correctly applied)
    • Global search: A state is remembered after refresh, and the filter text is displayed. In this case it is only possible to delete the filter by either selecting the search box and backspacing followed by ENTER or selecting the X followed by ENTER. I.e. it is no longer dynamic.
    1. Assuming State 1 is saved as above
    2. Refresh Page
    3. Type Arm in the “First Name” footer and select Create State (State 2)
    4. Refresh Page
    5. Select State 2 from “Saved States” (filter is correctly applied)
    6. Select the X in the Search box
    7. Press Enter key
    • If you apply a filter on an individual column search, save it, refresh the page and select the filter the filter will be applied (Correct). If you now select the appropriate footer box and backspace to remove the filter the display correctly shows the unfiltered table. If you now try and use the global search it will not work until you press return (it does not dynamically search). Likewise for removing text from the global search box.
    1. Assuming State 1 is saved as above
    2. Select State 1 from “Saved States” (filter is correctly applied)
    3. Select “First Name” footer and Backspace. Filter is removed.
    4. Enter a filter into the global search box. Nothing happens until you press ENTER

    Files:

            <!doctype html>
            <html>
            <head>
                <meta http-equiv="content-type" content="text/html; charset=utf-8" />
                <style>
                    tfoot input {
                        width: 100%;
                        padding: 3px;
                        box-sizing: border-box;
                    }
                </style>
    
                <title>StateSave Ajax Example</title>
    
                <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.3.3/css/dataTables.dataTables.css">
                <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/3.2.4/css/buttons.dataTables.css">
                <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/scroller/2.4.3/css/scroller.dataTables.css">
                <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/colreorder/2.1.1/css/colReorder.dataTables.css">
                <link rel="stylesheet" type="text/css" href="https://nightly.datatables.net/staterestore/css/stateRestore.dataTables.min.css">
    
                <script type="text/javascript" charset="utf-8" src="https://code.jquery.com/jquery-3.7.1.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/2.3.3/js/dataTables.js"></script>
    
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/buttons/3.2.4/js/dataTables.buttons.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/buttons/3.2.4/js/buttons.dataTables.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/scroller/2.4.3/js/dataTables.scroller.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/scroller/2.4.3/js/scroller.dataTables.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/buttons/3.2.4/js/buttons.colVis.min.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/colreorder/2.1.1/js/dataTables.colReorder.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://cdn.datatables.net/colreorder/2.1.1/js/colReorder.dataTables.js"></script>
                <script type="text/javascript" charset="utf-8" src="https://nightly.datatables.net/staterestore/js/dataTables.stateRestore.min.js"></script>
    
                <script type="text/javascript" charset="utf-8" src="js/jsontest.js"></script>
    
            </head>
    
            <body class="dataTables">
                    <h2>StateSave Ajax Example</h2>
                    <table id="example" class="display nowrap" style="width:100%">
                        <thead>
                            <tr>
                                <th>ID</th>
                                <th>First name</th>
                                <th>Last name</th>
                                <th>ZIP / Post code</th>
                                <th>Country</th>
                            </tr>
                        </thead>
                        <tfoot>
                            <tr>
                                <th>ID</th>
                                <th>First name</th>
                                <th>Last name</th>
                                <th>ZIP / Post code</th>
                                <th>Country</th>
                            </tr>
                         </tfoot>
                    </table>
            </body>
            </html>
    

        addEventListener("DOMContentLoaded", function () {
    
        new DataTable('#example', {
           initComplete: function () {
                this.api()
                    .columns()
                    .every(function () {
                        let column = this;
                        let title = column.footer().textContent;
    
                        // Create input element
                        let input = document.createElement('input');
                        input.placeholder = title;
                        column.footer().replaceChildren(input);
    
                        // Event listener for user input
                        input.addEventListener('keyup', () => {
                            if (column.search() !== this.value) {
                                column.search(input.value).draw();
                            }
                        });
                    });
            },
    
            ajax: {
                url: '../php/stateRestoreLoad.php',
                dataSrc: 'data'
            },
            layout: {
                topStart: {
                    buttons: [
                        'colvis',
                        'createState',
                        {
                            extend: 'savedStates',
                            config: {
                                ajax: '../php/stateRestoreSave.php'
                            }
                        }
                    ]
                }
            },
            scrollY: 200,
            colReorder: true,
            scrollCollapse: true
        });
        });
    

    I hope that this helps, sorry its so long winded.

  • allanallan Posts: 65,056Questions: 1Answers: 10,772 Site admin

    Hi,

    Apologies for the delay in replying here.

    Colvis: State not remembered after refresh
    colReorder: State not remembered after refresh

    Fixed with this commit, thank you!

    Individual column search: A state is remembered after refresh, however the filter text is not displayed even though the filter is working.

    That's because DataTables doesn't know anything about the input elements. There are two ways to address this:

    1. Use stateLoaded to populate the values into your column seach inputs
    2. Use ColumnControl which has column filtering ability and supports state saving.

    Global search: A state is remembered after refresh, and the filter text is displayed. In this case it is only possible to delete the filter by either selecting the search box and backspacing followed by ENTER or selecting the X followed by ENTER. I.e. it is no longer dynamic.

    Ooo. That's a good one. Made me think for a little bit :). Fix committed here.

    The final "quirk" should also have been resolved by the commits above :).

    Huge thanks for the report and feedback.

    Allan

Sign In or Register to comment.