Excelのデータをkintoneのテーブルにまとめてコピペしたい(出来そうで出来ないことの補強)

これまでExcelでデータを管理していて、それをkintoneでシステム化しようとした人なら、きっと一度は経験したことがあるのではないでしょうか。データ移行をするために、Excelからkintoneのテーブルへセルの値を一つずつコピーしたり、CSVファイルを作成してインポートしたりしなければなりません。こんなの他でやっているように画面から画面のコピペができたら、すいぶん楽なのに。手間のかかる作業は、ミスも発生しやすくなります。

では、Excelからkintoneへデータを素早くコピペする方法はないのでしょうか?

この記事では、kintoneをJavaScriptでカスタマイズし、Excelからkintoneのテーブルへ、Ctrl + C と Ctrl + V 操作だけでデータを直接貼り付けられるようにする方法を解説します。

準備アプリ
次のデータフィールドを含む「商品管理」アプリケーションを作成します。

フィールド名フィールドコードデータ型説明
商品一覧商品一覧テーブル商品の一覧を管理するテーブル
└ NoNo数値一覧内の商品に対する連番。
1から始まり順序を示す
└ 商品名商品名文字列(1行)商品の名称を入力する。
例:ボールペン、ノート
└ 数量数量数値商品の数量

JavaScriptプログラム

※「JSEdit for kintone」プラグインを使用して、ソースコードを編集します。JSEdit for kintone の画面から jQuery を追加・インストールすることで、HTML 要素のコーディングがより簡単になります。

プログラムの処理流れ

※この記事では、よりシンプルにするため、Excelのデータテーブル全体をkintoneにコピー&ペーストする方法のみを解説します。データの一部をコピー&ペーストするケースについては、今後の記事でご紹介する予定です。

  1. テーブル「商品一覧」のHTML要素を見つけます。 kintoneのすべての画面でHTML要素を取得する方法については、私の以前の記事を参考してください。
    参考; kintoneの新規・編集レコード画面のフィールドをカスタマイズする裏技
  2. 「商品一覧」テーブルのtbody要素を探す
    さらにテーブルの内部に入り、データ行(tr)を処理できるように、tbody要素にアクセスします。
  3. 最初の行の最初のセルを選択する
    「商品一覧」テーブルの最初の行(tr)の最初のセル(td)を選択し、その内部にあるinput要素を取得します。
  4. そのセルにユーザーが貼り付け(ペースト)した際のイベントを設定する
    ユーザーがExcelからデータを最初のセルに貼り付けた(ペーストした)際に、pasteイベントがトリガーされ、処理が実行されるように設定します。
  5. クリップボードからデータ(Excelからコピーされたデータ)を取得する
    ペースト時、ブラウザはクリップボードからデータを提供します。このデータをテキスト形式で取得します。
  6. データを解析する:行と列に分割する
    Excelのデータは通常、タブ(\t)と改行(\n)で区切られたテーブル形式です。このデータを、行と列のリストに分割します。
  7. Excelのデータをkintoneの「商品一覧」テーブルに割り当てる
    データの行数と列数に基づき、テーブル内の対応するtr要素とtd要素を検索し、その内部にある各input要素に値を割り当てます。
(($) => {
  // 変数 ELEMENT_FIELD_ID をフィールドコードとIDのマッピングとして作成します。
  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;
  }

  // レコード作成画面・編集画面の表示時に処理を実行
  kintone.events.on([
    'app.record.create.show', 
    'app.record.edit.show'
  ], (event) => {
    // サブテーブル「商品一覧」のHTMLクラス名を取得
    const subtableClass = `.subtable-${ELEMENT_FIELD_ID['商品一覧']}`;
    const tbody = $(`${subtableClass} tbody`);
    // サブテーブルのtbody(本体)要素を取得

    // 最初の行・最初のセルの<input>要素を取得
    const firstInput = tbody.find('tr').eq(0).find('td').eq(0).find('input');

    // 最初の<input>に「貼り付け」イベントを設定
    firstInput.on('paste', function (e) {
      e.preventDefault(); // ブラウザの標準貼り付け動作を無効化する

      // クリップボードのデータ(テキスト形式)を取得
      const clipboardData = e.originalEvent.clipboardData || window.clipboardData;
      const pastedText = clipboardData.getData('text');

      // 改行(\n)で行に分け、タブ(\t)で列に分けて2次元配列に変換
      const rows = pastedText.trim().split('\n').map(row => row.split('\t'));

      // サブテーブルのフィールドIDと現在のレコードデータを取得
      const subTableField = ELEMENT_FIELD_ID['商品一覧'];
      const record = event.record;

      // 各行をループして、表の該当位置に値を設定
      for (let i = 0; i < rows.length; i++) {
        const cols = rows[i];
        const tr = tbody.find('tr').eq(i);
        const tds = tr.find('td');

        // 各列をループして、対応する<input>に値を代入
        for (let j = 0; j < cols.length && j < tds.length; j++) {
          const input = tds.eq(j).find('input');
          input.val(cols[j]);
        }
      }
    });

    // 処理結果を返す
    return event;
  });
})(jQuery);

結果

記事を読んでいただきありがとうございます。
次の記事をお楽しみにお待ちください !

参照
クリップボード API