kintoneでテーブルの行をデータの昇順・降順で並べ替える

こんにちは! 私の名前はチュンです。
株式会社メディアフュージョンでkintone関連製品の開発を担当しているベトナム出身のエンジニアです。
kintoneに興味のある方、kintoneを使っている方に私の蓄積した経験を共有したいと思います。
kintoneのテーブルでデータを管理する際、データを昇順・降順に並び替える機能は不可欠な要件です。これにより、データの追跡、比較、および迅速な情報集計が容易になります。しかし、標準のkintoneにはこの機能が備わっていません。

この記事では、kintoneのテーブルをカスタマイズし、ヘッダーをクリックするだけでデータを自動的に昇順・降順にソートする方法を解説します。
準備アプリ
前回の記事で作成したアプリを引き続き使用します。
「Excelのデータをkintoneのテーブルにまとめてコピー&ペーストしたい(やれそうでやれないことの補完)」
JavaScriptプログラム
※「JSEdit for kintone」プラグインを使用して、ソースコードを編集します。JSEdit for kintone の画面から jQuery を追加・インストールすることで、HTML 要素のコーディングがより簡単になります。
プログラムの処理流れ
- サブテーブル「商品一覧」のHTML要素を特定する
cybozu.data.page[‘FORM_DATA’] を使用して、フィールドコードとHTMLクラス間のマッピングを作成します。
参考; kintoneの新規・編集レコード画面のフィールドをカスタマイズする裏技 - ヘッダーにソートアイコンを追加する
各ヘッダーセルに を追加し、↑↓の矢印アイコンを表示させます。
このアイコンにより、ソート方向(昇順/降順)を視覚的に示し、クリックで切り替えられるようにします。 - ヘッダーをクリックしてデータをソートする
a) ヘッダーのインデックスに基づいて、対応する列のフィールドコードを取得します。
b) 列のデータタイプを特定します:
NUMBER の場合、数値としてソートします。
例: [2, 10, 3] → 数値ソートで [2, 3, 10]
文字列ソート (localeCompare) を使うと [10, 2, 3] となり、正しい順序になりません。
その他のデータタイプの場合、文字列としてソートします。
例: [“B”, “A”, “C”] → ソートで [“A”, “B”, “C”]
c) 現在の状態に応じて、サブテーブルのデータ配列 (record[tableFieldCode].value) を昇順または降順にソートします。 - レコードを更新する
ソート後、kintone.app.record.set() を使ってレコードのデータを更新します。 - ソート状態を保存する
ヘッダーがクリックされるたびに、ソート状態(asc または desc)を保存し、次のクリック時にソート方向が切り替わるようにします。
(function() {
"use strict";
// FORM_DATAからサブテーブルのフィールドコードとHTMLクラス名をマッピング
const FORM_DATA = cybozu.data.page['FORM_DATA'];
const ELEMENT_FIELD_ID = {};
for (const subTableId of Object.keys(FORM_DATA.schema.subTable)) {
const subTable = FORM_DATA.schema.subTable[subTableId];
ELEMENT_FIELD_ID[subTable.var] = subTableId;
}
const tableFieldCode = '商品一覧'; // 対象のサブテーブルフィールドコード
// レコード作成・編集画面が表示されたときに処理
kintone.events.on(['app.record.create.show', 'app.record.edit.show'], function(event) {
// サブテーブル「商品一覧」のHTMLクラス名を取得
const subtableClass = `.subtable-${ELEMENT_FIELD_ID[tableFieldCode]}`;
// 各ヘッダーセルに対して処理
$(`${subtableClass} .subtable-label-gaia`).each(function(index){
const th = $(this);
// ソートアイコンがなければ追加
if(th.find('.sort-icon').length === 0){
th.append('<span class="sort-icon" style="font-size:20px; margin-right: 10px"></span>');
}
// クリックイベントを設定
th.off('click').on('click', function(){
// 最新のレコードデータを取得
const rec = kintone.app.record.get().record;
// 現在のソート状態を反転(昇順/降順)
const asc = !th.data('asc');
// 他のヘッダーのソートアイコンをリセット
$(`${subtableClass} .subtable-label-gaia .sort-icon`).text('');
// 現在のヘッダーにアイコン表示
th.find('.sort-icon').text(asc ? '↑' : '↓');
// クリックされた列のフィールドコードを取得
const fieldCode = Object.keys(rec[tableFieldCode].value[0].value)[index];
// フィールドのデータ型を取得(NUMBER / SINGLE_LINE_TEXT / ...)
const fieldType = rec[tableFieldCode].value[0].value[fieldCode].type;
// サブテーブルの値をソート
rec[tableFieldCode].value.sort(function(a, b){
const valA = a.value[fieldCode].value || ""; // 値が未入力の場合は空文字
const valB = b.value[fieldCode].value || "";
// データ型に応じてソート方法を変更
if(fieldType === 'NUMBER'){
// NUMBER型は数値としてソート
return asc ? (+valA) - (+valB) : (+valB) - (+valA);
} else {
// 文字列は文字順でソート
return asc ? valA.localeCompare(valB) : valB.localeCompare(valA);
}
});
// ソート結果をレコードに反映
kintone.app.record.set({record: rec});
// ソート状態を保存
th.data('asc', asc);
});
});
return event;
});
})();
結果

記事を読んでいただきありがとうございます。
次回の記事では、テーブルの各列のデータでフィルターをかける方法についてご説明します。ぜひお楽しみに!
参照

