且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

jqGrid列组

更新时间:2023-12-01 13:54:52

您的问题并不新鲜.很多时候,在trirand论坛或***上都提出了相应的功能请求.在一段时间之前,我就结束性问题给出了另一个答案. >

现在,在阅读完您的问题后,我决定不要提供支持所有jqGrid功能的完美解决方案(这太难了).取而代之的是,我决定创建一个可以在许多情况下使用但有一定限制的解决方案.

该演示显示了我的第一个结果:

限制:

  • 网格的列无法调整大小.我在demo cmTemplate: {resizable: false}参数中使用了所有网格列中的resizable: false.
  • 不支持
  • sortable: true
  • showColhideCol columnChooser 当前不受支持,但是我敢肯定,它可以迅速解决问题.
  • 将在其上放置其他列标题的列应具有相同的宽度.如果列的宽度值不同,则列的总宽度将自动 分在各列之间.

另一方面,在所有测试中,使用shrinkToFit: falseautowidth: true之类的其他流行选项,或者相对于setGridWidth方法更改网格宽度(带有或不带有收缩),一切都可以正常工作.

现在首先介绍该功能的用法.我写了函数insertColumnGroupHeader,在上面的示例中使用了

insertColumnGroupHeader(grid, 'amount', 3, '<em>Information about the Price</em>');

它将在HTML片段"关于价格的信息"中插入一个附加的列标题,该列标题从金额"列开始的3列中.因此用法非常简单.当然,您可以只使用诸如关于价格的信息"之类的任何文本作为附加的列标题.

函数insertColumnGroupHeader具有以下代码:

var denySelectionOnDoubleClick = function ($el) {
        // see https://***.com/questions/2132172/disable-text-highlighting-on-double-click-in-jquery/2132230#2132230
        if ($.browser.mozilla) {//Firefox
            $el.css('MozUserSelect', 'none');
        } else if ($.browser.msie) {//IE
            $el.bind('selectstart', function () {
                return false;
            });
        } else {//Opera, etc.
            $el.mousedown(function () {
                return false;
            });
        }
    },
    insertColumnGroupHeader = function (mygrid, startColumnName, numberOfColumns, titleText) {
        var i, cmi, skip = 0, $tr, colHeader, iCol, $th,
            colModel = mygrid[0].p.colModel,
            ths = mygrid[0].grid.headers,
            gview = mygrid.closest("div.ui-jqgrid-view"),
            thead = gview.find("table.ui-jqgrid-htable>thead");

        mygrid.prepend(thead);
        $tr = $("<tr>");
        for (i = 0; i < colModel.length; i++) {
            $th = $(ths[i].el);
            cmi = colModel[i];
            if (cmi.name !== startColumnName) {
                if (skip === 0) {
                    $th.attr("rowspan", "2");
                } else {
                    denySelectionOnDoubleClick($th);
                    $th.css({"padding-top": "2px", height: "19px"});
                    $tr.append(ths[i].el);
                    skip--;
                }
            } else {
                colHeader = $('<th class="ui-state-default ui-th-ltr" colspan="' + numberOfColumns +
                    '" style="height:19px;padding-top:1px;text-align:center" role="columnheader">' + titleText + '</th>');
                denySelectionOnDoubleClick($th);
                $th.before(colHeader);
                $tr.append(ths[i].el);
                skip = numberOfColumns - 1;
            }
        }
        mygrid.children("thead").append($tr[0]);
    };

此外,还需要在jqGrid代码中进行一些更改.您可以从 1884

var thd= $("thead:first",ts.grid.hDiv).get(0);
$("tr th:eq("+ts.p.lastsort+") span.ui-grid-ico-sort",thd).addClass('ui-state-disabled');
$("tr th:eq("+ts.p.lastsort+")",thd).attr("aria-selected","false");
$("tr th:eq("+idxcol+") span.ui-icon-"+ts.p.sortorder,thd).removeClass('ui-state-disabled');
$("tr th:eq("+idxcol+")",thd).attr("aria-selected","true");
if(!ts.p.viewsortcols[0]) {
    if(ts.p.lastsort != idxcol) {
        $("tr th:eq("+ts.p.lastsort+") span.s-ico",thd).hide();
        $("tr th:eq("+idxcol+") span.s-ico",thd).show();
    }
}

到以下:

var previousSelectedTh = ts.grid.headers[ts.p.lastsort].el,
    newSelectedTh = ts.grid.headers[idxcol].el;
$("span.ui-grid-ico-sort",previousSelectedTh).addClass('ui-state-disabled');
$(previousSelectedTh).attr("aria-selected","false");
$("span.ui-icon-"+ts.p.sortorder,newSelectedTh).removeClass('ui-state-disabled');
$(newSelectedTh).attr("aria-selected","true");
if(!ts.p.viewsortcols[0]) {
    if(ts.p.lastsort != idxcol) {
        $("span.s-ico",previousSelectedTh).hide();
        $("span.s-ico",newSelectedTh).show();
    }
}

接下来,我将getColumnHeaderIndex函数定义如下

var getColumnHeaderIndex = function (th) {
    var i, headers = ts.grid.headers, ci = $.jgrid.getCellIndex(th);
    for (i = 0; i < headers.length; i++) {
        if (th === headers[i].el) {
            ci = i;
            break;
        }
    }
    return ci;
};

并更改了 2172 2185 grid.base.js来自

var ci = $.jgrid.getCellIndex(this);

var ci = getColumnHeaderIndex(this);

就这些.上述更改应该对原始jqGrid代码没有负面影响,并且可以照常使用.下次,我将在trirand论坛上发布我的建议.

已更新:另一个版本演示的允许调整除具有标题的列以外的所有列的大小.在该版本中,将在其上放置附加列标题的所有列必须具有相同的宽度.列的宽度不会自动在列之间划分.您必须手动设置相同的列宽.

UDPATED 2 :我想介绍一下在创建更高级版本的多头jqGrid方面取得的一些进展.首先荒野 此处中查看其演示.顺便说一句,如果将jqGrid方法与我建议的修复程序一起使用(见上文),将解决演示中的图标排序问题.参见演示作为构象.

此后,我做了更多工作,但减少了使用rowSpan增加列高度的多列方法的限制.这是我当前的中间结果: 新演示 .在Internet Explorer 9/8,Firefox和Opera中,新的演示工作已经非常出色.在基于Webkit的浏览器(Google Chrome和Safari)中,它仍然具有上面列出的限制(具有多标题的列标题必须具有相同的大小,并且不能调整大小). 该演示看起来不错,但有限制,在Webkit-基于网络的浏览器.不过,您可以看到排序时间的进展.

我计划根据" >答案.因此,也将支持在列标题上使用许多标题. ColumnChooser或showCol/hideCol也将受支持.对我而言,现在最有趣的是找到一种清晰的方法,该方法如何在基于Webkit的浏览器(Google Chrome和Safari)中使用rowSpan来实现多行列标题.也许会有其他人找到解决方法?这是我决定在此处分享未完成的结果的主要原因.

更新3 :包括jqGrid代码中的更改(请参见演示.如果列宽将增加,第二个演示将增加网格宽度.我个人喜欢这种行为.

更新4 :该演示的下一个版本可以看到以下

can I implement a column group in jqGrid like the jQuery EasyUI library does?

You can figure out what I mean by going on the jQuery EasyUI demo web site, and choose Datagrid then Column Group from the left menu.

Thanks for helping

Your question is not new. Many times the corresponding feature request was asked in trirand forum or on the ***. I give another answer on the close question some time before.

Now after reading of your question I do decided don't make a perfect solution supporting all jqGrid features (which is too difficult at once). Instead of that I decide to create a solution which can be already used in many cases, but which has some restrictions.

The demo shows my first results:

The restrictions:

  • the columns of the grid can not be resized. I use in the demo cmTemplate: {resizable: false} parameter to set resizable: false in all grid columns.
  • sortable: true is not supported
  • showCol, hideCol or columnChooser are not currently supported, but I am sure that one can quickly fix the problems.
  • columns over which one will place an additional column header should has the same width. If the columns have different width values the total width of the column will be divided between the columns automatically.

On the other side everything work without any problem in all my tests with other popular options like shrinkToFit: false, autowidth: true or changing of the grid width with respect of setGridWidth method (with or without shrinking).

Now first about the usage of the feature. I wrote function insertColumnGroupHeader which I use in the above example as

insertColumnGroupHeader(grid, 'amount', 3, '<em>Information about the Price</em>');

It inserts an additional column header with the HTML fragment 'Information about the Price' over 3 columns starting with the column 'amount'. So the usage is pretty simple. You can of course use just any text like 'Information about the Price' as the additional column header.

The function insertColumnGroupHeader has the following code:

var denySelectionOnDoubleClick = function ($el) {
        // see https://***.com/questions/2132172/disable-text-highlighting-on-double-click-in-jquery/2132230#2132230
        if ($.browser.mozilla) {//Firefox
            $el.css('MozUserSelect', 'none');
        } else if ($.browser.msie) {//IE
            $el.bind('selectstart', function () {
                return false;
            });
        } else {//Opera, etc.
            $el.mousedown(function () {
                return false;
            });
        }
    },
    insertColumnGroupHeader = function (mygrid, startColumnName, numberOfColumns, titleText) {
        var i, cmi, skip = 0, $tr, colHeader, iCol, $th,
            colModel = mygrid[0].p.colModel,
            ths = mygrid[0].grid.headers,
            gview = mygrid.closest("div.ui-jqgrid-view"),
            thead = gview.find("table.ui-jqgrid-htable>thead");

        mygrid.prepend(thead);
        $tr = $("<tr>");
        for (i = 0; i < colModel.length; i++) {
            $th = $(ths[i].el);
            cmi = colModel[i];
            if (cmi.name !== startColumnName) {
                if (skip === 0) {
                    $th.attr("rowspan", "2");
                } else {
                    denySelectionOnDoubleClick($th);
                    $th.css({"padding-top": "2px", height: "19px"});
                    $tr.append(ths[i].el);
                    skip--;
                }
            } else {
                colHeader = $('<th class="ui-state-default ui-th-ltr" colspan="' + numberOfColumns +
                    '" style="height:19px;padding-top:1px;text-align:center" role="columnheader">' + titleText + '</th>');
                denySelectionOnDoubleClick($th);
                $th.before(colHeader);
                $tr.append(ths[i].el);
                skip = numberOfColumns - 1;
            }
        }
        mygrid.children("thead").append($tr[0]);
    };

Additionally it was required to make some changes in the jqGrid code. You can download the modified version (the modification of the 4.1.2 version) of jquery.jqGrid.src.js from here. The changes consist from two blocks. First I changed the code of sortData function, the lines 1874-1884

var thd= $("thead:first",ts.grid.hDiv).get(0);
$("tr th:eq("+ts.p.lastsort+") span.ui-grid-ico-sort",thd).addClass('ui-state-disabled');
$("tr th:eq("+ts.p.lastsort+")",thd).attr("aria-selected","false");
$("tr th:eq("+idxcol+") span.ui-icon-"+ts.p.sortorder,thd).removeClass('ui-state-disabled');
$("tr th:eq("+idxcol+")",thd).attr("aria-selected","true");
if(!ts.p.viewsortcols[0]) {
    if(ts.p.lastsort != idxcol) {
        $("tr th:eq("+ts.p.lastsort+") span.s-ico",thd).hide();
        $("tr th:eq("+idxcol+") span.s-ico",thd).show();
    }
}

to the following:

var previousSelectedTh = ts.grid.headers[ts.p.lastsort].el,
    newSelectedTh = ts.grid.headers[idxcol].el;
$("span.ui-grid-ico-sort",previousSelectedTh).addClass('ui-state-disabled');
$(previousSelectedTh).attr("aria-selected","false");
$("span.ui-icon-"+ts.p.sortorder,newSelectedTh).removeClass('ui-state-disabled');
$(newSelectedTh).attr("aria-selected","true");
if(!ts.p.viewsortcols[0]) {
    if(ts.p.lastsort != idxcol) {
        $("span.s-ico",previousSelectedTh).hide();
        $("span.s-ico",newSelectedTh).show();
    }
}

Next I defined getColumnHeaderIndex function as the following

var getColumnHeaderIndex = function (th) {
    var i, headers = ts.grid.headers, ci = $.jgrid.getCellIndex(th);
    for (i = 0; i < headers.length; i++) {
        if (th === headers[i].el) {
            ci = i;
            break;
        }
    }
    return ci;
};

and changed the lines 2172 and 2185 of grid.base.js from

var ci = $.jgrid.getCellIndex(this);

to

var ci = getColumnHeaderIndex(this);

It's all. The above described changes should have no negative influence on the original jqGrid code and can be used as usual. I will publish my suggestion in the next time on trirand forum.

UPDATED: Another version of the demo allows resizing of all columns excepting the columns having the headers. In the version all the columns over which one will place an additional column header have to have the same width. The width of the columns not divided between the columns automatically. You have to set the same column width manually.

UDPATED 2: I want to inform about some progress in creating more advanced version of multiheader jqGrid. First wildraid posted very interesting solution. See his demo here. By the way if one use with the method jqGrid with the fixes which I suggested (see above) the problem with sorting icons in the demo will be solved. See here the demo as the conformation.

After that I works a little more abut reducing restrictions in my multicolumn approach which use rowSpan to increase the height of the columns. Here is my current intermediate result: the new demo. The new demo work already very good in Internet Explorer 9/8, Firefox and Opera. In Webkit-based browsers (Google Chrome and Safari) it has still the above listed restriction (column headers which has multiheaders have to have the same size and be not resizable). The demo looks good has the restrictions and it looks good in Webkit-based web browsers. Nevertheless you can see progress in the sort time.

I plan to increase the height of the resizable area used to resize the columns based on the demo from the answer. Of cause the usage of many headers over column headers will be also supported. ColumnChooser or showCol/hideCol will be supported too. The most interesting for me now is to finding a clear way how to implement multirows column headers using rowSpan in Webkit-based browsers (Google Chrome and Safari). Probably somebody else will find a solution way? It is the main reason why I decide to share not completed results here.

UPDATE 3: The changes in the code of jqGrid are included (see here) in the main code of jqGrid. I improved the solution which I described here to this and this demos. The second demo increase the grid width if the column width will be increased. I personally like the behavior.

UPDATE 4: The next version of the demo you can see here. It has an boolean option (the parameter useColSpanStyle) which which defines whether colspan should be used or not. With false value of the parameter the results will be the following.