Possible bug using ColVis and stateSave (with save and load Ajax call) together

Possible bug using ColVis and stateSave (with save and load Ajax call) together

davidhiglerdavidhigler Posts: 3Questions: 0Answers: 0

Hello DataTables,

I'm seriously impressed with DataTables and all of it's options.
Never have I seen a library on datatables so complete and extendable.
Loving it!

The reasing I'm posting is because i'm running into a problem that I can't solve, despite hours of debugging.
I'm using the ColVis extension and the saveState stateSave functionality.
If the saveState functionality uses the local storage (HTML5) the ColVis extension works perfectly without problems.
But when I use the stateSaveCallback stateSaveCallback and stateLoadCallback stateLoadCallback to save and load the state server-side into the database something weird happens with the ColVis extension.
The state is loaded and saved correctly into the database with Ajax calls but if a make a column visible again after hiding it it will position the header th correctly but will position the corresponding td of each row at the end of the row in stead of the correct position.
Also the saved visibility of a column is not restored when using the saveState functionality.

I've tried using the latest stable versions and the latest nightly builds, but nothing seems to work.
Can you please help me?

<script language="javascript">
    $(document).ready(function() {
        var owoningbeheerwoningendatatable = $('#woningbeheerwoningendatatable').DataTable( {
            'dom': "RC<'clear'><'row'<'col-xs-12 col-sm-6 col-md-6 col-lg-6'Tl>r>t<'row'<'col-xs-3 col-sm-4 col-md-5'i><'col-xs-9 col-sm-8 col-md-7 text-right'p>>",
            'processing': true,
            'serverSide': true,
            'responsive': true,
            'stateSave': true,
            'ajax': {
                'url': '/woningbeheer/datatables/woningenjson'
            },
            'lengthMenu': [ [ 10, 25, 50, 75, 100, 250, 500, -1 ], [ 10, 25, 50, 75, 100, 250, 500, 'Alles' ] ],
            'order': [ [ 1, 'asc' ] ],
            'colVis': {
                'buttonText': 'Toon / verberg kolommen',
                'overlayFade': 0,
                'exclude': [ 0 ]
            },
            'stateSaveCallback': function (settings, data) {
                $.ajax({
                    'url': '/datatables/state/save',
                    'data': { 'identifier': 'woningbeheerwoningendatatable', 'data': data },
                    'dataType': 'json',
                    'method': 'POST'
                });
            },
            'stateLoadCallback': function (settings) {
                var o;
                $.ajax({
                    'url': '/datatables/state/load',
                    'data': { 'identifier': 'woningbeheerwoningendatatable' },
                    'async': false,
                    'dataType': 'json',
                    'method': 'POST',
                    'success': function (json) {
                        o = json;
                    }
                });
                return o;
            },
            'stateSaveParams': function (settings, data) {
                for (var i = 0; i < data.columns.length; i++) {
                    data.columns[i].search.search = '';
                }
                data.search.search = '';
            },
            'tableTools': {
                'sSwfPath': '/metronics/global/swf/copy_cvs_xls_pdf.swf',
                'aButtons': []
            },
            'columns': [
                {
                    'name': 'complexnummer',
                    'title': 'Complex',
                    'className': 'string complexnummer tooltips',
                    'tooltip': 'Het complexnummer van desbetreffende woning.',
                    'type': 'string',
                    'orderable': true,
                    'searchable': true,
                    'visible': true,
                    'data': {
                        'select': 'complex.complexnummer',
                        '_': 'complexnummer',
                        'filter': 'complexnummer',
                        'display': 'complexnummer'
                    },
                },
                {
                    'name': 'vhe_nummer',
                    'title': 'VHE',
                    'className': 'string vhe_nummer tooltips',
                    'tooltip': 'Het VHE nummer van desbetreffende woning.',
                    'type': 'string',
                    'orderable': true,
                    'searchable': true,
                    'visible': false,
                    'data': {
                        'select': 'woning.vhe_nummer',
                        '_': 'vhe_nummer',
                        'filter': 'vhe_nummer',
                        'display': 'vhe_nummer'
                    },
                },
                {
                    'name': 'straat',
                    'title': 'Straat',
                    'className': 'string straat tooltips',
                    'tooltip': 'De straatnaam van de woning.',
                    'type': 'string',
                    'orderable': true,
                    'searchable': true,
                    'visible': true,
                    'data': {
                        'select': 'woning.straat',
                        '_': 'straat',
                        'filter': 'straat',
                        'display': 'straat'
                    },
                },
                {
                    'name': 'huisnummer',
                    'title': 'Huisnr',
                    'className': 'integer huisnummer tooltips',
                    'tooltip': 'Het huisnummer van desbetreffende woning.',
                    'type': 'integer',
                    'orderable': true,
                    'searchable': true,
                    'visible': true,
                    'data': {
                        'select': 'woning.huisnummer',
                        '_': 'huisnummer',
                        'filter': 'huisnummer',
                        'display': 'huisnummer'
                    },
                },
                {
                    'name': 'toevoeging',
                    'title': 'Toev',
                    'className': 'string toevoeging tooltips',
                    'tooltip': 'De toevoeging aan het huisnummer van het adres van desbetreffende woning.',
                    'type': 'string',
                    'orderable': true,
                    'searchable': true,
                    'visible': true,
                    'data': {
                        'select': 'woning.toevoeging',
                        '_': 'toevoeging',
                        'filter': 'toevoeging',
                        'display': 'toevoeging'
                    },
                },
                {
                    'name': 'postcode',
                    'title': 'Postcode',
                    'className': 'string postcode tooltips',
                    'tooltip': 'De postcode van het adres.',
                    'type': 'string',
                    'orderable': true,
                    'searchable': true,
                    'visible': true,
                    'data': {
                        'select': 'woning.postcode',
                        '_': 'postcode',
                        'filter': 'postcode',
                        'display': 'postcode'
                    },
                }
            ]
        });

    });
</script>

Replies

  • allanallan Posts: 63,208Questions: 1Answers: 10,415 Site admin

    The problem isn't that ColVis doesn't work with state saving, but rather that Responsive is being used ('responsive': true,).

    Responsive controls the column visibility, so it is inherently incompatible with ColVis which also attempts to control the column visibility (I'm going to add a note to the documentation to highlight this as it has come up a few times recently, or possibly a warning in the code).

    Basically there becomes a bit of a race condition between ColVis and Responsive, and only one of them will win. Usually Responsive...

    Allan

  • davidhiglerdavidhigler Posts: 3Questions: 0Answers: 0

    Allen,

    Thanks for the quick response.
    I've removed the responsive option, but the problem is still there.
    When I remove the saved state from the database so the first load state gets an empty response the problem is gone. But when a saved state is returned after a reload the problem returns.

    Below the php json_encode string from my database.

    Could it be because the integers and boolean variables are converted to strings (as it seems) that the problem is caused?
    If so, the problem is with the way I save and return the state json.

    {  
       "time":"1418374615726",
       "start":"0",
       "length":"25",
       "order":[  
          [  
             "1",
             "asc"
          ]
       ],
       "search":{  
          "search":"",
          "smart":"true",
          "regex":"false",
          "caseInsensitive":"true"
       },
       "columns":[  
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"false",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          },
          {  
             "visible":"true",
             "search":{  
                "search":"",
                "smart":"true",
                "regex":"false",
                "caseInsensitive":"true"
             }
          }
       ],
       "ColReorder":[  
          "0",
          "1",
          "2",
          "3",
          "4",
          "5",
          "6",
          "7",
          "8",
          "9",
          "10"
       ]
    }
    
  • davidhiglerdavidhigler Posts: 3Questions: 0Answers: 0

    Never mind!
    The problem was indeed that the values where casted to strings.
    Many thanks though for the responsive removal tip.

  • allanallan Posts: 63,208Questions: 1Answers: 10,415 Site admin

    Good to hear. Yes - the string 'true' and 'false' will both be "true" in the loose checking that DataTables uses there. It need to retain he original Javascript data type.

    Allan

  • landanohrlandanohr Posts: 1Questions: 0Answers: 0

    Hi!

    In advance sorry for my poor english (i promise that write java better than english). And great work in the page!!

    I´m trying to integrate a full datatable with some extensions, like colVis and responsive, in a bootstrap development .
    As you mention colVis and responsive appear to be incompatible; so i try to solve it modifying the source (version 1.10.4):

    ...
    //first: save original information about visibility (loaded by colVis + statesave)
    _classLogic: function ()
        {
            var that = this;
            var calc = {};
            var breakpoints = this.c.breakpoints;
            var columns = this.s.dt.columns().eq(0).map( function (i) {
                var className = this.column(i).header().className;
                //original >> none
                var completeCol = this.context[0].aoColumns[i]; // <<<<< change
    
                return {
                    className: className,
                    includeIn: [],
                    auto:      false,
                    control:   false,
                    never:     className.match(/\bnever\b/) ? true : false,
                    //original >> none
                    completeCol:   completeCol // <<<<< change
                };
            } );
    ...
    
    ...
    //second: use saved information for calculate the column visibility
    _columnsVisiblity: function ( breakpoint )
        {
            var dt = this.s.dt;
            var columns = this.s.columns;
            var i, ien;
    
            // Class logic - determine which columns are in this breakpoint based
            // on the classes. If no class control (i.e. `auto`) then `-` is used
            // to indicate this to the rest of the function
            var display = $.map( columns, function ( col ) {
                //original >> return col.auto && col.minWidth === null ?
                return col.auto && (col.minWidth === null || !col.completeCol.bVisible) ? // <<<<< change
                    false :
                    col.auto === true ?
                        '-' :
                        $.inArray( breakpoint, col.includeIn ) !== -1;
            } );
    ...
    
    
    ...
    //third: modify creation for '+' button; not working fine for hide column '0'
    _detailsVis: function ()
        {
            var that = this;
            var dt = this.s.dt;
    
            // Find how many columns are hidden
            var hiddenColumns = dt.columns().indexes().filter( function ( idx ) {
                var col = dt.column( idx );
    
                if ( col.visible() ) {
                    return null;
                }
    
                // Only counts as hidden if it doesn't have the `never` class
                //original >> return $( col.header() ).hasClass( 'never' ) ? null : idx;
                return $( col.header() ).hasClass( 'never' ) ? null : true; // <<<<< change
            } );
    ...
    

    I´m testing yet, but it works for the moment. I hope it serves!!

    Bye!!

  • allanallan Posts: 63,208Questions: 1Answers: 10,415 Site admin

    ColVis and Responsive both attempt to control column visibility state. Therefore without hacks they simply cannot operate together.

    Allan

This discussion has been closed.