kintoneでテーブルの行をドラッグ&ドロップで並び替える (パート2)

前回は、Excelのようにkintoneのテーブル行をドラッグ&ドロップで並び替える方法をご紹介しました。ただし、これはあくまで画面上の操作であり、並び替えた順番は保存されません。
 前回記事; kintoneでテーブルの行をドラッグ&ドロップで並び替える(パート1)
今回の記事では、ドラッグ&ドロップで並び替えた行の順番をレコードに保存する方法をご紹介します。

プログラムの処理手順

  1. jQuery UIのsortableを使って、テーブルの行をドラッグ&ドロップ可能にする。
  2. 行を移動する前と後のインデックス(oldIndex と newIndex)を記録する。
  3. kintone.app.record.get() を使って、現在のレコードのデータを取得する。
  4. oldIndex → newIndex に従って、レコード内の行の順番を入れ替える。
  5. kintone.app.record.set() を使って、変更後のデータをレコードに保存する。

ソースコード

(() => {
  'use strict';
      // フォームデータの取得
    let FORM_DATA = cybozu.data.page['FORM_DATA'];
    let ELEMENT_FIELD_ID = {};
    let fieldList = FORM_DATA.schema.table.fieldList;
    for (let fieldId of Object.keys(fieldList)) {
      ELEMENT_FIELD_ID[fieldList[fieldId].var] = fieldId;
    }
    for (const subTableId of Object.keys(FORM_DATA.schema.subTable)) {
      ELEMENT_FIELD_ID[FORM_DATA.schema.subTable[subTableId].var] = subTableId;
    }
  // レコード作成・編集画面を表示したときに発火するイベント
  kintone.events.on([
    'app.record.create.show', 'app.record.edit.show'
  ], (event) => {
    let tableHTML = $(`.subtable-${ELEMENT_FIELD_ID['注文一覧']}`);
    
    let oldIndex; // ドラッグ開始時の行インデックスを記録するための変数
    
    // jQuery UIのsortable機能を適用(ドラッグ&ドロップ可能にする)
    tableHTML.sortable({
      items: "tr",          // 各テーブル行を対象に
      cursor: "move",       // カーソルを移動アイコンに
      axis: "y",            // 縦方向のみ移動可能

      // ドラッグ開始時の処理
      start: function(event, ui) {
        // 選択行にスタイル適用(視覚的にわかりやすくする)
        ui.item.css({
          "background-color": "#fff9c4",
          "box-shadow": "0 4px 10px rgba(0, 0, 0, 0.2)"
        });

        // 移動前のインデックスを記録
        oldIndex = ui.item.index();
      },

      // ドラッグ終了時の処理
      stop: function(event, ui) {
        const newIndex = ui.item.index(); // 移動後のインデックス

        // スタイルをリセット
        ui.item.css({
          "background-color": "",
          "box-shadow": ""
        });
        // kintoneレコードデータの取得
        let record = kintone.app.record.get().record; 

        // サブテーブルのデータをロジック上で並び替え
        let movedItem = record["注文一覧"].value.splice(oldIndex, 1)[0]; // 移動対象を一旦削除
        record["注文一覧"].value.splice(newIndex, 0, movedItem);           // 新しい位置に挿入

        // 並び替えた内容をkintoneレコードに反映
        kintone.app.record.set({record: record});
      }
    });

    return event;
  });
})();

最初の結果

データの保存には成功しましたが、ドラッグ&ドロップの動作が正しくありませんでした

調査の結果、原因は kintone.app.record.set() がデータを更新すると同時に、画面にもその変更を反映するため、jQuery UI の sortable 機能と競合してしまうことにあると判明しました。

解決策

jQuery UI の sortable 機能によるドラッグ&ドロップの操作は、行の新しい位置(インデックス)を記録する目的でのみ使用し、DOM 上の HTML 要素の順番は実際には変更しないようにします。
そのために、sortableのstopイベント内で $(this).sortable('cancel'); を追加し、HTML要素の並び替えを無効化します。

stop: function(event, ui) {
   const newIndex = ui.item.index(); 
   ui.item.css({
     "background-color": "",
      "box-shadow": ""
   });

   // 実際のDOM移動をキャンセル(表示上のみドラッグ)
   $(this).sortable('cancel');

   let record = kintone.app.record.get().record; 
   let movedItem = record["注文一覧"].value.splice(oldIndex, 1)[0]; 
   record["注文一覧"].value.splice(newIndex, 0, movedItem);           
   kintone.app.record.set({record: record});
}

最終結果


次回の記事では、kintoneの画面をExcelのようにシートで分割する方法をご紹介します。どうぞお楽しみに!