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 stackoverflow. 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:
cmTemplate: {resizable: false}
parameter to set resizable: false
in all grid columns.sortable: true
is not supportedshowCol
, hideCol
or columnChooser are not currently supported, but I am sure that one can quickly fix the problems.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://stackoverflow.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.