jqGridの小技たち1（行結合、列結合）

業務で使っているのですが、毎回忘れるのでメモ。

# バージョン
- jquery：2.1.1
- jquery-ui：1.11.1
- jqGrid：4.6.0

# ヘッダに改行を入れる
単純にcolNamesの指定の中で<br />タグを埋め込めばOKですが、これだけだと改行した部分が表示されないので、以下のようにヘッダの高さを調整する必要があります。

```testGrid.js
colNames: ['long<br />text', 'Status']
```

```testGrid.html
<style type="text/css">  
<!--
.ui-jqgrid .ui-jqgrid-htable th {
    height: 70px;
}
.ui-jqgrid .ui-jqgrid-htable th div {
    height: 35px;
}
-->
</style>
※リストが複数ある場合は先頭にIDを指定してあげるとそのリストにのみ適用されます
```

# ヘッダの列結合
結合はできるのですが、2行になってしまうようです。今回はそれでいいやと思って詳しくは調べていません。

setGroupHeadersを使用します。

```testGrid.js
    $("#list").jqGrid({
     ～省略～
    });
    $("#list").jqGrid('setGroupHeaders', {
        useColSpanStyle: true,
        groupHeaders: [
          { startColumnName: 'content1', numberOfColumns: 4, titleText: 'content group' },
        ]
    });
```
- useColSpanStyle：2行になるので、これをtrueにすると他の行を自動で行結合してくれます
- startColumnName：どの列から結合するか。colModelで指定したnameを指定します
- numberOfColumns：何列結合するか
- titleText：結合列ヘッダに表示する文字列

こちらを参考にしました。
[Common rules]
(http://www.trirand.com/jqgridwiki/doku.php?id=wiki:groupingheadar)


# データの列結合
colModelの指定の中で、cellattrにcolspanを指定してあげればOKです。
ただし、結合する先頭列にcolspan、結合される列にはdisplay:noneを指定する必要があります。

```testGrid.js
colModel: [
            {
                name: 'content1', index: 'content1', width: 100, align: 'center', hidden: false,
                cellattr: function (rowId, tv, rawObject, cm, rdata) {
                    if (rdata.type == 'aaa') { return ' colspan=2' }
                    else if (rdata.type == 'bbb') { return ' colspan=4' }
                }
            },
            {
                name: 'content2', index: 'content2', width: 80, align: 'center', hidden: false,
                cellattr: function(rowId, tv, rawObject, cm, rdata) {
                    if (rdata.type == 'aaa' || rdata.type == 'bbb') { return ' style="display:none;"' }
                }
            },
```

この場合、type列が'aaa'の場合は2列結合、'bbb'の場合は4列結合しています。
cellattrの中で自由に条件指定できるのはありがたいですね。


こちらを参考にしました。
[stackOverFlow - How to merge cells in jqGrid 4.0 -](http://stackoverflow.com/questions/5625325/how-to-merge-cells-in-jqgrid-4-0)

# データの行結合
静的データでは簡単なのかもしれないが、Ajax等で動的にデータを取得している場合はやや面倒。

afterInsertRowで行追加処理をする前にbeforeProcessingでデータを確認する必要があります。
今回の要件の場合、上の行と同じ値だったら結合するという内容でした。
あんまり綺麗なソースじゃありませんが。。。

```testGrid.js

var rowStyleList = new Array();

/**
 * グリッドを作成する
 */
function createGrid() {
    $("#list").jqGrid({
     ～省略～

        /**
         * 行追加の前に呼ばれる処理
         */
        beforeProcessing: function () {
            // 行スタイルリストの作成
            createRowStyleList();
        },
        /**
         * 行生成
         */
        afterInsertRow: function (rowid, aData) {
            $("#list").setColProp('column1', {
                cellattr: function (rowId, value, rowObject, colModel, arrData) {
                    // スタイル設定
                    if (rowStyleList.length != 0) {
                        return rowStyleList[rowId - 1][1];
                    }
                }
            });
        },
     ～省略～
    });
}

/**
 * 行スタイルリストを作成する
 */
function createRowStyleList() {

    var rowIDs = $("#list").getDataIDs(); // データ取得
    var prevColumn1 = '';  // 前の行のデータ
    var spanCount = 1;  // 結合行数
    var combTopId = 0;  // 結合の先頭行番号

    var styleList = new Array();

    // 行解析
    var len = rowIDs.length;
    for (var i = 0; i < len; i++) {
        var item = rowIDs[i];
        var column1 = $("#list").getCell(item, 'column1');

        if (prevColumn1 == column1) {
            // 前の行と同じ場合
            spanCount++;
            var rowInfoList = new Array(3); // 0:結合先頭行番号、1:スタイル、2:結合行数（結合先頭行のみ）
            rowInfoList[0] = combTopId + 1;
            rowInfoList[1] = ' style=display:none; '; // 同じなので表示しない
            rowInfoList[2] = 0;
            styleList[i] = rowInfoList;

            if (i + 1 == len) {
                // 最終行の場合
                var rowLastList = new Array(3);
                rowLastList[0] = combTopId + 1;
                rowLastList[1] = ' rowspan=' + spanCount;
                rowLastList[2] = spanCount;
                styleList[combTopId] = rowLastList;
            }
        }
        else {
            // 前の行と違う
            if (i != 0) {
                // 先頭行でない場合
                if (spanCount != 1) {
                    // 複数行の場合
                    var rowInfoList = new Array(3);
                    rowInfoList[0] = combTopId + 1;
                    rowInfoList[1] = ' rowspan=' + spanCount;  // 結合1行目
                    rowInfoList[2] = spanCount;
                    styleList[combTopId] = rowInfoList;

                    if (i + 1 == len) {
                        // 最終行の場合
                        var rowLastList = new Array(3);
                        rowLastList[0] = i + 1;
                        rowLastList[1] = '';
                        rowLastList[2] = 0;
                        styleList[i] = rowLastList;
                    }
                }
                else {
                    // 単一行の場合
                    var rowInfoList = new Array(3);
                    rowInfoList[0] = i;
                    rowInfoList[1] = '';
                    rowInfoList[2] = 0;
                    styleList[i - 1] = rowInfoList;

                    if (i + 1 == len) {
                        // 最終行の場合
                        var rowLastList = new Array(3);
                        rowLastList[0] = i + 1;
                        rowLastList[1] = '';
                        rowLastList[2] = 0;
                        styleList[i] = rowLastList;
                    }
                }

                spanCount = 1;
            }

            combTopId = i;
        }
        prevColumn1 = column1;
    }

    rowStyleList = styleList;
}
```

※ソースそのまま貼れないので一部抜粋しています。そのままでは動作しないかもしれません。なんとなく伝われば。

ちなみにデータ数が多いと結合されるのに気持ち時間がかかります。
もっと簡単にできる方法があればご指南ください。


# （2017/09/21追加）ヘッダの列結合に伴う列のズレ修正

最近遭遇して解決できたので追記。
ヘッダの列結合をしたはいいものの、なぜかヘッダ列とデータ列の列幅がずれて表示されてしまいました。
ネットにはそれっぽい情報はあったのですが解決できず、調べたところ以下で解決できました。

```html
<style type="text/css">
<!--
#gview_list .ui-jqgrid-htable{
    table-layout: auto;
}
-->
</style>
```

`#gview_***`の部分は適時自分のリスト名に書き換えてください。