Resizing columns using JQuery UI

Resizing columns using JQuery UI

FurburgerFurburger Posts: 37Questions: 8Answers: 0

If you want to allow a user to drag and resize columns, you can use the https://github.com/jeffreydwalter/ColReorderWithResize but it is still a bit buggy despite recently being re-factored and comes with a lot of additional code for re-ordering columns which over-complicates it unnecessarily.

The difficulty in resizing columns by dragging the column headers arises if you are using the Scroller because DataTables creates two tables - one for the ScrollHeader and another for the ScrollBody

After much trial and error, I tried using JQueryUI's resizable functionality and it works quite well.

I cannot give you a fully working solution because the code is entwined in a large project, but below are some steps to get you going in the right direction:

Step 1: Add JQueryUI

JqueryUI can add add a lot bloatware to your project, but for resizing, you only need the following:

import "jquery-ui/ui/widget.js"; 
import "jquery-ui/ui/widgets/mouse.js"; 
import "jquery-ui/ui/disable-selection.js"; 
import "jquery-ui/ui/widgets/resizable.js"; 
import 'jquery-ui/themes/base/core.css';
import 'jquery-ui/themes/base/resizable.css';

Step 2: Add some CSS to change the table layout to fixed and the cell overflow to ellipse

.table.dataTable {
    table-layout: fixed;
    width: 100%;
}

.table.dataTable th {
    white-space: nowrap;
    overflow: hidden;
}

.table.dataTable td {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

Step 3: Make the column headings of the ScrollHead table reizable()

Add the following code to the InitComplete callback of your DataTable:

initComplete: function(settings) {

    let tableId = $(this)[0].id; // Get the table id

    //Add JQueryUI resizable functionality to each th in the ScrollHead table

    $('#' + tableId + '_wrapper .dataTables_scrollHead thead th').resizable({

        handles: "e",

        alsoResize: '#' + tableId + '_wrapper .dataTables_scrollHead table', //Not essential but makes the resizing smoother

        stop: function() {

            // User has stopped dragging the column

            //Call your own function to save the widths of each column - localStorage is a good choice
            saveColumnSettings(); 

            //Call your own function which adjust the columnDefs to use the new (saved) widths and then reload the DataTable
            loadDataTable(); 
        }
    });
},

This is how I implemented it on a recent project and it works surprisingly well. Play around with it yourself - I offer it only as a pointer in the right direction. The custom functions to save the widths and reload DatatTables you will have to customize and figure out yourself. I just hope it will give you some food for thought and maybe save you the days and days I spent trying other methods unsuccessfully.

Replies

  • colincolin Posts: 12,948Questions: 0Answers: 2,206

    Thanks for that. I tried it here out of interest - guess it needs the save functions completed.

    Colin

  • FurburgerFurburger Posts: 37Questions: 8Answers: 0

    Your attempt is not working too well.

    I forgot to mention that you should also set autoWidth to false otherwise DataTables keeps trying to resize the columns itself.

    I initially define columnDefs in an array (setting the widths as percentages) before loading the table:

    let tableColumnDefs = [
        {
             title: "Name",
             width: "12%",
             data: null,
             targets: 0,
             render: (data) => { return data.name }
         },
    etc...
    

    I then set columnDefs to this array when creating the DataTable

    $('#example').DataTable({
       autoWidth: false,
       destroy: true,
       columnDefs: tableColumnDefs,
       etc..
    })
    

    On the Stop event of the JQueryUI drag operation, I simply update the tableColumnDefs array with the new widths (now in px) and reload the DataTable.

    Here is some example code to get the new widths (in px)

    table.columns().every( function () {
           header = this.header();
           width = $(header).width();
    });
    

    It works very well once you have all this in place.

  • kthorngrenkthorngren Posts: 14,175Questions: 25Answers: 3,345

    Maybe you can build a running example that we can look at. You can update Colin's example to show as a demo.

    Kevin

  • FurburgerFurburger Posts: 37Questions: 8Answers: 0

    OK - I have made a working example in JS Bin.

    Have a look at it here: live.datatables.net/coqiwimi/1/edit

  • kthorngrenkthorngren Posts: 14,175Questions: 25Answers: 3,345

    Looks good, thanks!

    Kevin

  • colincolin Posts: 12,948Questions: 0Answers: 2,206

    That's excellent, thanks for sharing,

    Colin

Sign In or Register to comment.