12

So I'm trying to use the flexigrid plugin. It looks like it's going to work great aside from the fact that it looks like you have to manually set the column widths. Otherwise, the column headers do not match up with the body columns.

Is there any way of automatically matching these up, while still allowing the column widths to be defined by the length of the content in the columns (as is the normal table behavior).

Yusubov
  • 5,815
  • 9
  • 32
  • 69
Joel Martinez
  • 46,929
  • 26
  • 130
  • 185

12 Answers12

9

My solution is a lot simpler than the others suggested.

Before you call the flexigrid function, add this:

$("#yourtable th").each(function() {
  $(this).attr("width", $(this).width());
});

This will set the width of the column headers to as wide as the text in them is (as opposed to manually setting each header width either with css or in the markup) and make the table body columns the same width.

Flexo
  • 87,323
  • 22
  • 191
  • 272
Vibeke
  • 111
  • 1
  • 2
9

I had this problem as well. Here is my fix, and it works great. In flexigrid.js around line 678, change this line.

$(tdDiv).css({textAlign:pth.align,width: $('div:first',pth)[0].style.width});

to this

$(tdDiv).css({textAlign:pth.align,width: $('div:first',pth).width() + "px"});

And you are all set.

Brian
  • 91
  • 1
  • 1
4

I've gotten this to work (at least partially). The problem I was having with my previous iteration (which was also a problem with tvanfosson's implementation) was that once you resized the headers, then the "drag" bars would not be aligned with the new column widths.

My current implementation is below, which works in Firefox 3.5 and Chrome. Unfortunately, there is some exception being thrown in IE (all versions) that is rather disconcerting. I will debug further on Monday:

$(".flexigrid").each(function() {
    var grid = $(this);
    var headers = grid.find(".hDiv thead th");
    var row = grid.find(".bDiv tbody tr:first");
    var drags = grid.find("div.cDrag div");
    if (row.length >= 1) {
        var cells = row.find("td");
        var offsetAccumulator = 0;
        headers.each(function(i) {
            var headerWidth = $(this).width();
            var bodyWidth = cells.eq(i).width();
            var realWidth = bodyWidth > headerWidth ? bodyWidth : headerWidth;

            $(this).width(realWidth);
            cells.eq(i).width(realWidth);

            var drag = drags.eq(i);
            var dragPos = drag.position();
            var offset = (realWidth - headerWidth);
            var newPos = dragPos.left + offset + offsetAccumulator;
            offsetAccumulator += offset;
            drag.css("left", newPos);
        });
    }
});
Joel Martinez
  • 46,929
  • 26
  • 130
  • 185
  • I had to fix a few gotchas in Flexigrid as well. Around line 1000 it needs to check the results of the parseInt calls to make sure they are numbers (set to 0 otherwise). Around line 960 it needs to check if this.width has a value (set to 'auto') before appending 'px' to it. – tvanfosson Jul 29 '09 at 18:55
  • yeah, that was the cause of the IE issue I described above. Once it was patched it started working a peach – Joel Martinez Jul 29 '09 at 19:07
  • Updated my code to handle the drags as well. Note that my code now finds the widest column in the table and uses that as the default width. – tvanfosson Jul 29 '09 at 20:05
  • I found that I needed to use outerWidth() on IE or I had an off by 1px error on the headers. I'm still using IE7 so YMMV. – tvanfosson Jul 29 '09 at 20:35
3

I've been working on this today, too. What I've come up with involves adding an onSuccess handler and figuring out what the maximum size of each column is between the header and the body, then setting the width of both to the maximum for that column.

grid.flexigrid({

  ...other setup...

  onSuccess: function() {
       format();
    });
  }
});

function format() {
    var gridContainer = this.Grid.closest('.flexigrid');
    var headers = gridContainer.find('div.hDiv table tr:first th:not(:hidden)');
    var drags = gridContainer.find('div.cDrag div');
    var offset = 0;
    var firstDataRow = this.Grid.find('tr:first td:not(:hidden)');
    var columnWidths = new Array( firstDataRow.length );
    this.Grid.find( 'tr' ).each( function() {
        $(this).find('td:not(:hidden)').each( function(i) {
            var colWidth = $(this).outerWidth();
            if (!columnWidths[i] || columnWidths[i] < colWidth) {
                columnWidths[i] = colWidth;
            }
        });
    });
    for (var i = 0; i < columnWidths.length; ++i) {
        var bodyWidth = columnWidths[i];

        var header = headers.eq(i);
        var headerWidth = header.outerWidth();

        var realWidth = bodyWidth > headerWidth ? bodyWidth : headerWidth;

        firstDataRow.eq(i).css('width',realWidth);
        header.css('width',realWidth);            
        drags.eq(i).css('left',  offset + realWidth );
        offset += realWidth;
    }
}
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • Hmm, I actually ended up writing extremely similar code earlier :-P however, I was getting some strange error in IE only. Let me try your version and let's see how it goes :-) – Joel Martinez Jul 24 '09 at 23:55
1

From your own answer, I added setting min-width so that the columns don't get squeezed differently if the flexigrid width was set too narrow or the flexigrid resized, tested only in chrome:

    $(this).width(realWidth);
    cells.eq(i).width(realWidth);
    // these two lines added
    $(this).css('min-width', realWidth);
    cells.eq(i).css('min-width',realWidth);

Just doing this break column resizing, as that modifies the width of the div inside the th and td, but that can be fixed with a few additional lines in flexigrid in the "dragEnd" function:

. . .
// LINE 211
$('th:visible div:eq(' + n + ')', this.hDiv).css('width', nw);
// ADD THIS AFTER LINE 211
$('th:visible div:eq(' + n + ')', this.hDiv).parent().css('min-width', nw);
$('th:visible div:eq(' + n + ')', this.hDiv).parent().css('width', nw);
. . .
// LINE 214
$('td:visible div:eq(' + n + ')', this).css('width', nw);
// ADD THIS AFTER LINE 214
$('td:visible div:eq(' + n + ')', this).parent().css('width', nw);
$('td:visible div:eq(' + n + ')', this).parent().css('min-width', nw);
plockc
  • 4,241
  • 3
  • 18
  • 9
1

Similar issue for me. Have a page with 3 tabs, each with a flexigrid. Only one of the tabs had issue where header cell was somehow shorter than the data cells underneath of it. Which also threww off the alignment of all the header cells following that one.

.. what I figured out by inspecting the rendered elements using Chrome's CTRL+SHIFT+J functionality and inspecting down inside the <div class="hDiv" element... eventually finding the <th abbr="MyColumnName"field... was that the width: <nnn>pxpart wasn't even there!

Went back and inspected where I was defining colModel and noticed for just that one column... instead of width: <MyWidthValueHere>, I had inadvertently typed Width: <MyWidthValueHere>, instead (First letter caps vs all lowercase). It was such a subtle difference my eyes weren't catching it when initially scrutinizing and compare/contrasting the tabs that worked against this one that had the issue.

TheGDog
  • 21
  • 6
1

Thanks. Based on the post of line 678, mine got fixed with the following:

$(tdDiv).css({textAlign:pth.align,width: $('div:first',pth).width()-10 + "px"});

For some reason, the header font is larger than the detail font... hope this helps.

CoolBeans
  • 20,654
  • 10
  • 86
  • 101
Joe
  • 11
  • 1
0

This one worked for me:

    onSuccess : function(){
         $('#flex1 > tbody').wrap('<table cellpadding="0" cellspacing="0" />');
    },

Add this to the flexgrid construction options. flex1 is your flexgrid div id.

Moshe.

0

This code work fine in my project. It's similar to other answers.

$("#my_table").flexigrid({
    ...
    onSuccess: function(){
        columnWidth();
        $(window).resize(function(){
            columnWidth();
        });
    }
});

function columnWidth(){
    var num_col = 0;
    //Work with the columns width of the first row of body
    $("#row1 td").each(function(td){
        //row's column's width greater than header's column's width 
        if($(this).width() > $("th[axis='col"+num_col+"']").width()){
            $("th[axis='col"+num_col+"']").width($(this).width());
            $("th[axis='col"+num_col+"']").css({"min-width":$(this).width()});
        }
        //header's column's width greater than row's column's width
        else if($("th[axis='col"+num_col+"']").width() > $(this).width()){
            $("td[abbr='"+$(this).prop('abbr')+"']").width($("th[axis='col"+num_col+"']").width());
            $("td[abbr='"+$(this).prop('abbr')+"']").css({"min-width":$("th[axis='col"+num_col+"']").width()});
        }
        ++num_col;
    });
}

I hope this has solved your problems.

Vegekku
  • 1
  • 2
0

I ran into the same thing, finding out that the width of my divs containing the column headings and the table cells had the width = 0. So i had to wait a bit until the whole html-table was built, then i had to run the "format" method. Next thing is that i have the HTML table built in an invisible div at the beginning. So i had to omit the not(:hidden) selector within my code.

Here we go:

    $.fn.flexAddData = function(data) { // function to add data to grid
       ...
    };
    // my own method to justify the column headers with the body
    $.fn.flexFormat = function() {
        return this.each(function() {
            var gridContainer = $('.flexigrid');
            var headers = gridContainer.find('.hDiv table tr:first th');
            var firstDataRow = gridContainer.find('.bDiv table tr:first td');
            var offSet = 10;
            // for each element in headers
            // compare width with firstDataRow elemts
            // the greater one sets the width of the lower one
            $.each(headers, function(i) {
                var thWidth = $(this).find('div').outerWidth();
                var tdWidth = $(firstDataRow[i]).find('div').outerWidth();

                thWidth > tdWidth ? $(firstDataRow[i]).find('div').width(thWidth - offSet) : $(this).find('div').width(tdWidth - offSet);

            });
        });
    }; // end format

The call for the method as follows:

    setTimeout(function() {
            $('.flexigrid').flexFormat();
        }
        , 10
    );

Hope to have another solution for the problem ;-) Regards, Christoph

Echilon
  • 10,064
  • 33
  • 131
  • 217
0

Found this elsewhere:

Figured it out - for anyone with a similar problem: I had it assigned to a <div id="mygrid">, when I assigned it to a <table id="mygrid"> everything worked great!

http://markmail.org/message/kibcuxu3kme2d2e7

Scott
  • 21,211
  • 8
  • 65
  • 72
YUri
  • 9
  • 1
0

I know this will come as odd to some, but I was having the same problem and once I rearranged my layout (the whole page, not the grid itself) everything was fine.

I had a 3-column fluid layout. I moved the grid to the very top of the page, right after the body tag, and it lined up perfectly! Wow...

bladnman
  • 2,591
  • 1
  • 25
  • 20