Consistent grid headers with Flexigrid ?

2019-03-11 10:00发布

问题:

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).

回答1:

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;
    }
}


回答2:

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.



回答3:

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.



回答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);
        });
    }
});


回答5:

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.



回答6:

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);


回答7:

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.



回答8:

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...



回答9:

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



回答10:

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.



回答11:

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



回答12:

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.