Setting jqGrid column width from titles

Lately I’ve been playing a lot with jqGrid, a very nice Grid / Table plugin for jQuery / jQuery UI. It does some really amazing things including allowing you to have a scrollbar that replaces the standard “next page” / “previous page” that you see in most web applications. I have tables that are sortable on multiple columns that have tens of thousands of results and I can scroll through them easily. It is also easy to leverage filtering, etc. All this takes a touch of server-side code, but it is all astoundingly easy.

The one trick I couldn’t figure out how to do was to set the column with based on the Title. In most grids with just a few columns, this isn’t an issue – you set the size (in pixels) and go on your way. But what if you don’t know the column names ahead of time (they come from the database) and you just want to make sure the column with is a minimum of a number but a maximum big enough to hold the title plus a bit of padding?

After the grid has been created, you cannot programmatically set the width of columns, so it has to be done before the grid is created. Normally you create a jqGrid as such:

    <table id="list"></table>
    <div id="pager"></div>
    <script type="text/javascript">
        var colNamesData = ['Inv No','Date Of the Transaction', 'Amount That Is Owed'];
        var colModelData = [
            {name:'invid', index:'invid', width:55},
            {name:'invdate', index:'invdate', width:90},
            {name:'amount', index:'amount', width:80, align:'right'}];
        jQuery(document).ready(function(){
        jQuery("#list").jqGrid({
            ...
            colNames: colNamesData,
            colModel: colModelData,
            ...
        });
    </script>

To set the column widths automatically to the title, for any column in the column model I added a new boolean attribute resizeToTitleWidth and only resized the column if this was set to true. Here is the new code that resizes the desired columns.

    <table id="list"></table>
    <div id="pager"></div>
    <span id='ruler' class='ui-th-column' style='visibility:hidden;font-weight:bold'></span>
    <script type="text/javascript">
        var colNamesData = ['Inv No','Date Of the Transaction', 'Amount That Is Owed'];
        var colModelData = [
            {name:'invid', index:'invid', width:55},
            {name:'invdate', index:'invdate', resizeToTitleWidth:true},
            {name:'amount', index:'amount', align:'right', resizeToTitleWidth:true}];
        jQuery(document).ready(function() {
            var ruler = document.getElementById('ruler');
            for (var i in colNamesData) {
                if (colModelData[i].resizeToTitleWidth != true) {
                    continue;
                }
                // Measure the title using the ruler span
                ruler.innerHTML = colNamesData[i];
                // The +26 allows for padding and to fit the sorting UI
                var newWidth = ruler.offsetWidth + 26;
                if (newWidth < 100) {
                    // Nothing smaller than 100 pixels
                    newWidth = 100;
                }
                colModelData[i].width = newWidth;
            }
            jQuery("#list").jqGrid({
                ...
                colNames: colNamesData,
                colModel: colModelData,
                shrinkToFit:false,
                ...
        });
    </script>

The key to obtaining the width is the additional hidden HTML span tag with the id of ruler.  This hidden span has the same CSS style as the column header, so we can place the column title text into this span and obtain the width of the text geting the span‘s offsetWidth. After we have the width, we pad the width with enough extra space to hold the sorting UI.

It would have been nice if the column had an attribute that forced the width to accommodate the the columns title (but allowed for a minimum width, here 100 pixels) but we find that it isn’t too difficult to add the functionality ourselves.

The above example is meant to be illustrative rather that a complete working sample. I’ve put together what should be a simple, working sample you can try.

12 thoughts on “Setting jqGrid column width from titles”

  1. I get an error, ‘colNames is undefined’. Doesn’t like this line,

    “ruler.innerHTML = colNames[i];

    Any idea?

    Thanks.

  2. Thanks, no error. However my column headers still don’t line up. I have been looking everywhere for a solution.
    What am I doing wrong?

    Thanks

    Here is my code:

    My First Grid

    var mystr = “197825010000270324033440004425197926010400290348037545004725198029011600310372041750005100198131012400340408045955005550198234013600370444050060006075198337014800410492055066006675198439015600430516058069607050198541016400450540061073207425198644017600480576056087007875198746018400500600068081608175198847018800510612070084008400198950020000540648074088808925199052020800570684078093609525199154021600590708081097209900199257022800620744085010200103501993590236006407680880105601072519946202480067080409301116011250199563025200680816094011280113251996640256006908280104212500116251997670268007208640112513500121501998700280007609120120914500126751999740296008009600129215500134252000780312008401008014171700014175200183033200890106802084250001492520028703480094011280250030000157502003890356009601152025603072016125200490036000970116402590310801627520059203680010001200026503180016725200697038800104012480277033240174752007100040000108012960287034440181502008105042000113013560301036120189752009109043600118014160314037680198002010112044800000019800”

    var colNamesData = [‘Year’,’Earn’, ‘Amt 1 QC’,’Amt 4 QC’,’# of QCs’,’M’,’YrFRA’,’MthlyYr’,’YrFRA’,’YOC’];
    var colModelData = [
    {name:’year’, index:’year’, resizeToTitleWidth:true, sorttype:false},
    {name:’earn’, index:’earn’, resizeToTitleWidth:true, sortable:false},
    {name:’1qc’, index:’1qc’, resizeToTitleWidth:true, sorttype:false},
    {name:’4qc’, index:’4qc’, resizeToTitleWidth:true, sorttype:false},
    {name:’numqc’, index:’numqc’, resizeToTitleWidth:true, sorttype:false},
    {name:’mfra’, index:’mfra’, resizeToTitleWidth:true, sorttype:false},
    {name:’yfra’, index:’yfra’, resizeToTitleWidth:true, sortable:false},
    {name:’myafra’, index:’myafra’, resizeToTitleWidth:true, sortable:false},
    {name:’yafra’, index:’yafra’, resizeToTitleWidth:true, sortable:false},
    {name:’yoc’, index:’yoc’, resizeToTitleWidth:true, sortable:false} ]
    jQuery(document).ready(function(){
    var ruler = document.getElementById(‘ruler’);
    for (var i in colNamesData) {
    if (colModelData[i].resizeToTitleWidth != true) {
    continue;
    }
    // Measure the title using the ruler span
    ruler.innerHTML = colNamesData[i];
    // The +26 allows for padding and to fit the sorting UI
    var newWidth = ruler.offsetWidth + 26;
    if (newWidth < 100) {
    // Nothing smaller than 100 pixels
    newWidth = 100;
    }
    colModelData[i].width = newWidth;
    }
    jQuery("#list").jqGrid({
    datatype: 'xmlstring',
    datastr : mystr,
    colNames: colNamesData,
    colModel : colModelData,
    pager: '#pager',
    rowNum:10,
    //rowNum:numRows,
    //viewrecords: true,
    //height: 'auto',
    //height: 'auto'
    //autowidth: true,
    //gridview: true,
    //forceFit: true,
    //width: 810,
    height: 350,
    caption: 'Grid'

    });
    });

  3. I’ve updated the above example with a couple minor things AND if you look at the bottom I now include a complete example that should help. This uses default fonts so the +26 offset isn’t quite enough, it seems, but hopefully it will help.

  4. Thanks for the sample code, I used the sample code and I still have the same problem. I’m guessing it’s my XML data: “var mystr =”

  5. My overall recommendations would be

    1. Make your Javascript as simple as possible
    2. Use Firebug (plugin for Firefox) as it will make debugging Javascript, HTML, and CSS much simpler.
    3. Web Developer Toolbar and Aardvark (other Firefox plugins) can also be very helpful. But if you just add one plugin, it needs to be Firebug.

  6. I took your advise and peeked around with firebug. I know where I need to change the width but I don’t know how to do it.

    It’s in a th tag, I need to change the width.

    th class=”ui-state-default ui-th-column ui-th-ltr” role=”columnheader” style=”width: 55px;”

    any idea?

    Thanks

  7. 1. Did my sample project resize the 2nd and 3rd columns for you as expected?
    2. Did you add resizeToTitleWidth:true to the columns in column model that you want to have resized?
    3. Did you add the span to your HTML?
    4. Did you add the code I wrote to resize the columns if resizeToTitleWidth is true? This changes the column model BEFORE the grid is made to set the width on the appropriate columns. It uses the ruler to assist with doing so.
    5. Did you step through my code, using Firebug, to see that it was finding the columns to resize and appropriately resizing?

    The problem with Javascript is that if you have a typo, missing comma, etc. it just silently stops processing the Javascript. Firebug helps with this.

    If you have Firebug installed, you can add logging lines to your Javascript

    console.log(“some message”);

    and see the logging messages in Firebug’s console to see that various parts of your code are running.

  8. After further review, it was my XML string.
    I was missing a column of data, which was throwing the whole thing off.

    Thanks for your help.

Leave a Reply to Noe Cancel reply

Your email address will not be published. Required fields are marked *