【intra-mart】imuiListTableで行結合する方法

今回は、intra-mart標準で用意されているタグimuiListTableで実装した表に行結合を実装していく方法について記載します。
公式ドキュメントでは、ヘッダのグループ化についてのサンプルはありますが、データの行結合についての記載は見つけられなかったのでお役に立てればうれしいです。

## 開発形式
- intra-mart AccelPlatform
    - スクリプト開発

## 完成イメージ
これが
![beforTable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513590/3bb73dbe-29e4-4062-f494-e581f78ea29f.png)

こう！
![afterTable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513590/959ddef6-a598-2423-c8b8-4bf52c72e9ac.png)

## 下準備
まずは、結合前のシンプルな表を作成していきます。
基本的なスクリプト開発モデルプログラミングについては公式ドキュメントをご参照ください。

```html:sample.html
<IMART type="head">
	<script src="ui/libs/jquery-validation-1.9.0/jquery.validate.js"></script>
	<script src="ui/js/imui-form-util.js"></script>
</IMART>
<div class="imui-form-container-wide" align="center">
	<IMART type="imuiListTable" data=sampleData height="300">
		<cols>
			<col name="col1" caption="フロー名" />
			<col name="col2" caption="未完了/完了" />
			<col name="col3" caption="最終ステータス" />
			<col name="col4" caption="案件数" />
		</cols>
	</IMART>
</div>
```
```javascript:sample.js
const sampleData = [
	{ 'col1': 'フローA', 'col2': '未完了', 'col3': '未完了', 'col4': '30' },
	{ 'col1': 'フローA', 'col2': '完了', 'col3': '承認', 'col4': '48' },
	{ 'col1': 'フローB', 'col2': '未完了', 'col3': '未完了', 'col4': '10' },
	{ 'col1': 'フローB', 'col2': '完了', 'col3': '承認', 'col4': '21' },
	{ 'col1': 'フローB', 'col2': '完了', 'col3': '否認', 'col4': '14' },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '承認', 'col4': '85' },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '否認', 'col4': '10' },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '取下げ', 'col4': '3' },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '案件操作', 'col4': '1' },
	{ 'col1': 'フローD', 'col2': '未完了', 'col3': '未完了', 'col4': '42' },
];

function init(request) { }
```
これで、画像のようなページが作成できました。
![beforTable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513590/3bb73dbe-29e4-4062-f494-e581f78ea29f.png)

## 行結合の実装
では早速行結合の実装です。
実装の流れは以下の通りです。
1. 結合する行数をデータに持たせる
1. 行結合処理を、クライアントサイドjavaScriptで実装
1. imuiListTableの該当列に2で作成した関数を呼び出す属性を追加

それぞれ詳しく見て行きます。

### 1. 結合する行数をデータに持たせる
今回は単純に結合する行数をデータに持たせます。
```javascript:sample.js
const sampleData = [
	{ 'col1': 'フローA', 'col2': '未完了', 'col3': '未完了', 'col4': '30', 'col1SpanNum': 2, 'col2SpanNum': 1 },
	{ 'col1': 'フローA', 'col2': '完了', 'col3': '承認', 'col4': '48', 'col1SpanNum': 0, 'col2SpanNum': 1 },
	{ 'col1': 'フローB', 'col2': '未完了', 'col3': '未完了', 'col4': '10', 'col1SpanNum': 3, 'col2SpanNum': 1 },
	{ 'col1': 'フローB', 'col2': '完了', 'col3': '承認', 'col4': '21', 'col1SpanNum': 0, 'col2SpanNum': 2 },
	{ 'col1': 'フローB', 'col2': '完了', 'col3': '否認', 'col4': '14', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '承認', 'col4': '85', 'col1SpanNum': 4, 'col2SpanNum': 4 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '否認', 'col4': '10', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '取下げ', 'col4': '3', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '案件操作', 'col4': '1', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローD', 'col2': '未完了', 'col3': '未完了', 'col4': '42', 'col1SpanNum': 1, 'col2SpanNum': 1 },
];
```
col1SpanNumがcol1の結合数、col2SpanNumがcol2の結合数です。
ここで注意が、結合数を記載するのは、最初にそのデータが出るときということです。
2回目以降のデータでは0を指定します。
理由は後述します。

### 2. 行結合処理を、クライアントサイドjavaScriptで実装
結合対象となるcolタグのonCellAttr属性に関数を指定して、動的にスタイル属性を付与するイメージです。
スタイル属性を返却する関数は、今回は以下のように定義しました。
```html:sample.html
<script>
	function setAttr(rowId, val, rawObject, cm, rdata) {
		if (cm.name == "col1") {
			if (rawObject.col1SpanNum == 0) {
				return "style=display:none;";
			} else {
				return "rowspan=" + rawObject.col1SpanNum;
			}
		}

		if (cm.name == "col2") {
			if (rawObject.col2SpanNum == 0) {
				return "style=display:none;";
			} else {
				return "rowspan=" + rawObject.col2SpanNum;
			}
		}

	}
</script>
```
ここで重要なところが、結合のスタイルだけでなく、非表示のスタイルも返すというところ。
結合されるレコードのセルをそのままにしておくと、後続の列がずれていってしまうため、
非表示とする必要があります。

### 3. imuiListTableの該当列に2で作成した関数を呼び出す属性を追加
前述で実装した関数を、結合対象となるcolタグに指定します。
```html:sample.html
<div class="imui-form-container-wide" align="center">
	<IMART type="imuiListTable" data=sampleData height="300">
		<cols>
			<col name="col1" caption="フロー名" onCellAttr="setAttr" />
			<col name="col2" caption="未完了/完了" onCellAttr="setAttr"  />
			<col name="col3" caption="最終ステータス" />
			<col name="col4" caption="案件数" />
		</cols>
	</IMART>
</div>
```
これで、行結合した表の完成です。
![afterTable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513590/959ddef6-a598-2423-c8b8-4bf52c72e9ac.png)

# まとめ
最終的なソースはこちら。
```html:sample.html
<IMART type="head">
	<script src="ui/libs/jquery-validation-1.9.0/jquery.validate.js"></script>
	<script src="ui/js/imui-form-util.js"></script>
	<script>
		function setAttr(rowId, val, rawObject, cm, rdata) {
			if (cm.name == "col1") {
				if (rawObject.col1SpanNum == 0) {
					return "style=display:none;";
				} else {
					return "rowspan=" + rawObject.col1SpanNum;
				}
			}

			if (cm.name == "col2") {
				if (rawObject.col2SpanNum == 0) {
					return "style=display:none;";
				} else {
					return "rowspan=" + rawObject.col2SpanNum;
				}
			}

		}
	</script>
</IMART>

<div class="imui-form-container-wide" align="center">
	<IMART type="imuiListTable" data=sampleData height="300">
		<cols>
			<col name="col1" caption="フロー名" onCellAttr="setAttr" />
			<col name="col2" caption="未完了/完了" onCellAttr="setAttr" />
			<col name="col3" caption="最終ステータス" />
			<col name="col4" caption="案件数" />
		</cols>
	</IMART>
</div>
```
```javascript:sample.js
const sampleData = [
	{ 'col1': 'フローA', 'col2': '未完了', 'col3': '未完了', 'col4': '30', 'col1SpanNum': 2, 'col2SpanNum': 1 },
	{ 'col1': 'フローA', 'col2': '完了', 'col3': '承認', 'col4': '48', 'col1SpanNum': 0, 'col2SpanNum': 1 },
	{ 'col1': 'フローB', 'col2': '未完了', 'col3': '未完了', 'col4': '10', 'col1SpanNum': 3, 'col2SpanNum': 1 },
	{ 'col1': 'フローB', 'col2': '完了', 'col3': '承認', 'col4': '21', 'col1SpanNum': 0, 'col2SpanNum': 2 },
	{ 'col1': 'フローB', 'col2': '完了', 'col3': '否認', 'col4': '14', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '承認', 'col4': '85', 'col1SpanNum': 4, 'col2SpanNum': 4 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '否認', 'col4': '10', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '取下げ', 'col4': '3', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローC', 'col2': '完了', 'col3': '案件操作', 'col4': '1', 'col1SpanNum': 0, 'col2SpanNum': 0 },
	{ 'col1': 'フローD', 'col2': '未完了', 'col3': '未完了', 'col4': '42', 'col1SpanNum': 1, 'col2SpanNum': 1 },
];

function init(request) { }
```
今回はサーバサイドjavaScriptにてデータを定義して実装していますが、
もちろんSQL等を用いて動的に取得する場合も活用できます。
HTMLタグの仕様については、公式ドキュメントをご参照ください。

ではまた。Good hack！(￣▽￣)ﾉ