Table column sort gets 'stuck' on ascending (asc)

Table column sort gets 'stuck' on ascending (asc)

nickardonickardo Posts: 5Questions: 1Answers: 0

Hello all,

My company uses datatables throughout our app so I wrote a class to make it easier to implement each instance of the table. We're using server side processing with .net API endpoint.

The class works fine except for some reason the column sorting is exhibiting weird behavior. It essentially gets stuck and will only sort by ascending. I can sort by descending once, then click header again and it will sort by ascending, then subsequent clicks will sort by only ascending.

I tried running the datatables debugger tool but it does not seem to work :(

I believe the problem has something to do with how I'm saving and loading the state. We're saving the state to a database. If I get rid of the stateSaveCallback and stateStateLoadCallback the sorting works fine. The reason I'm saving the state to the database is that we want to persist the user's settings across computers/sessions.

Below are the relevant parts of the class (creating the table and stateSave and stateLoad (I didn't include the other methods in the class).

Thanks for reading and any help is greatly appreciated.

"use strict";

export default class AcmeDataTable {
    constructor({ tableId, parentType, searchId, rowRecId, url, initCompleteFunctions = [], rowClickHandler, rowDoubleClickHandler, rowElementClickHandler, columns, getFiltersFunction }) {
        this.tableId = tableId;
        this.parentType = parentType;
        this.searchId = searchId;
        this.rowRecId = rowRecId;
        this.url = url;
        this.initCompleteFunctions = initCompleteFunctions;
        this.rowClickHandler = rowClickHandler;
        this.rowDoubleClickHandler = rowDoubleClickHandler;
        this.rowElementClickHandler = rowElementClickHandler;
        this.columns = columns;
        this.getFiltersFunction = getFiltersFunction;
        this.initialize = true;
        this.uniqueId = crypto.randomUUID();
        this.init();
    };

    init() {
        this.createDataTable();
        this.addCustomizeGridCallbacks();
    };
async createDataTable() {
        const state = await this.loadState.bind(this)();

        this.table = $(`#${this.tableId}`)
            .DataTable({
                select: "single",
                rowId: this.rowRecId,
                serverSide: true,
                processing: true,
                language: {
                    processing:
                        "<span><i class='fas fa-circle-notch fa-spin' aria-hidden='true''></i>   Processing</span>",
                },
                ajax: {
                    url: this.url,
                    type: "GET",
                    contentType: "application/json",
                    dataType: "json",
                    headers: {
                        Authorization: "Bearer " + Acme.getCookie("jwtToken").replace("token=", ""),
                    },
                    data: function (d) {
                        d.order[0].dir = d.order[0].dir === "asc" ? 0 : 1;

                        const request = {
                            filters: this.getFiltersFunction(),
                            params: {
                                ...d,
                                search: document.getElementById(this.searchId)?.value
                            }
                        };

                        return {
                            request: JSON.stringify(request)
                        };
                    }.bind(this),
                    error: function (xhr, error, code) {
                        if (
                            xhr &&
                            xhr.responseText != "" &&
                            xhr.responseText != undefined
                        ) {
                            Acme.DisplayBanner(xhr.responseText, "alert-danger");
                        }
                        alert("error")
                    },
                    dataSrc: function (response) {
                        response.recordsTotal = response.data.recordsTotal;
                        response.recordsFiltered = response.data.recordsFiltered;
                        return response.data.data;
                    },
                },
                cache: false,
                page: 0,
                columns: this.columns,
                colDefs: [
                    { targets: "dateColumn", visible: false }
                ],
                stateSave: true,
                stateSaveCallback: (settings, state) => {
                    this.saveState(state);
                },
                stateLoadCallback: () => state,
                colReorder: {
                    realtime: false,
                },
                scrollX: true,
                scrollY: true,
                scrollCollapse: true,
                searching: true,
                paging: true,
                pagingType: "full_numbers",
                dom: "rt<\"bottom\"lp>",
                drawCallback: function (settings) {
                    this.table.columns.adjust();
                    this.selectDefaultRow();
                }.bind(this),
                initComplete: function (settings, json) {
                    this.initCompleteFunctions.forEach(fn => fn(settings, json));
                    this.attachRowClickEvent();
                    this.attachRowDoubleClickEvent();
                    this.attachCheckboxClickEvent();
                    if (!state) this.saveState(this.table.state());
                }.bind(this),
            });
    };

  async saveState(data) {
        data.start = 0 //ensure first page is start page

        if (this.initialize === true) {
            this.initialize = false;
            return;
        }

        if (this.customizing) {
            // skip saving state if customizing
            return;
        }

        data.names = this.getNameOrder();
        await Acme.WriteProperty(`${this.tableId}.${this.parentType}`, JSON.stringify(data));
    };

 async loadState() {
        const state = await Acme.ReadProperty(`${this.tableId}.${this.parentType}`);
        return state ? JSON.parse(state) : null;
    }
}

Replies

  • allanallan Posts: 63,445Questions: 1Answers: 10,465 Site admin

    Happy to take a look at a test case showing the issue.

    Allan

  • nickardonickardo Posts: 5Questions: 1Answers: 0

    @Allan

    I messaged you regarding a test case. If my message isn't the right next step I can try and create a js bin test case.

  • allanallan Posts: 63,445Questions: 1Answers: 10,465 Site admin

    Thanks - I'll take a look at it in the morning.

    Allan

  • allanallan Posts: 63,445Questions: 1Answers: 10,465 Site admin

    Thanks for the link. Could you do me a favour at load the datatables.js file, rather than datatables.min.js for a bit? The minified code is proving difficult to debug :).

    FYI, the DataTables debugger doesn't work on the page as jQuery appears to be getting loading more than once on the page. The second one is wiping out the one with DataTables attached to it. That isn't what is causing the issue being seen here though!

    Allan

  • nickardonickardo Posts: 5Questions: 1Answers: 0

    Hi @allan, I changed our cdn to use unminified datatable.js.

  • allanallan Posts: 63,445Questions: 1Answers: 10,465 Site admin

    Thanks for that. However, did it get deployed? I'm still seeing the include as:

    <script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.23/cr-1.5.2/fc-3.3.1/fh-3.1.7/sc-2.0.2/sl-1.3.1/datatables.min.js"></script>
    

    I've done a cache reset to make sure that wasn't the issue.

    One thing in addition to that, have you tried the latest version of DataTables?

    <script src="https://cdn.datatables.net/v/bs4/dt-1.13.4/cr-1.6.2/fc-4.2.2/fh-3.3.2/sc-2.1.1/sl-1.6.2/datatables.js"></script>
    

    Will get you the latest version of everything for DataTables. The related CSS is:

    <link href="https://cdn.datatables.net/v/bs4/dt-1.13.4/cr-1.6.2/fc-4.2.2/fh-3.3.2/sc-2.1.1/sl-1.6.2/datatables.min.css" rel="stylesheet"/>
    

    Allan

  • nickardonickardo Posts: 5Questions: 1Answers: 0

    @allan

    Hmm, you tried our QA environment?

    https://qa.themortgageoffice.com/

    Maybe it hadn't yet been deployed when you tried it? Looking at it now it appears to be using the unminified version:

    https://cdn.datatables.net/v/bs4/dt-1.10.23/cr-1.5.2/fc-3.3.1/fh-3.1.7/sc-2.0.2/sl-1.3.1/datatables.js

    We haven't updated to the latest version as of yet. I can give that a try.

Sign In or Register to comment.