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

こんにちは! 私の名前はチュンです。
株式会社メディアフュージョンでkintone関連製品の開発を担当しているベトナム出身のエンジニアです。
kintoneに興味のある方、kintoneを使っている方に私の蓄積した経験を共有したいと思います。
これまでExcelでデータを管理していて、それをkintoneでシステム化しようとした人なら、きっと一度は経験したことがあるのではないでしょうか。データ移行をするために、Excelからkintoneのテーブルへセルの値を一つずつコピーしたり、CSVファイルを作成してインポートしたりしなければなりません。こんなの他でやっているように画面から画面のコピペができたら、すいぶん楽なのに。手間のかかる作業は、ミスも発生しやすくなります。
では、Excelからkintoneへデータを素早くコピペする方法はないのでしょうか?

この記事では、kintoneをJavaScriptでカスタマイズし、Excelからkintoneのテーブルへ、Ctrl + C と Ctrl + V 操作だけでデータを直接貼り付けられるようにする方法を解説します。
準備アプリ
次のデータフィールドを含む「商品管理」アプリケーションを作成します。
| フィールド名 | フィールドコード | データ型 | 説明 |
| 商品一覧 | 商品一覧 | テーブル | 商品の一覧を管理するテーブル |
| └ No | No | 数値 | 一覧内の商品に対する連番。 1から始まり順序を示す |
| └ 商品名 | 商品名 | 文字列(1行) | 商品の名称を入力する。 例:ボールペン、ノート |
| └ 数量 | 数量 | 数値 | 商品の数量 |
JavaScriptプログラム
※「JSEdit for kintone」プラグインを使用して、ソースコードを編集します。JSEdit for kintone の画面から jQuery を追加・インストールすることで、HTML 要素のコーディングがより簡単になります。
プログラムの処理流れ
※この記事では、よりシンプルにするため、Excelのデータテーブル全体をkintoneにコピー&ペーストする方法のみを解説します。データの一部をコピー&ペーストするケースについては、今後の記事でご紹介する予定です。
- テーブル「商品一覧」のHTML要素を見つけます。 kintoneのすべての画面でHTML要素を取得する方法については、私の以前の記事を参考してください。
参考; kintoneの新規・編集レコード画面のフィールドをカスタマイズする裏技 - 「商品一覧」テーブルのtbody要素を探す
さらにテーブルの内部に入り、データ行(tr)を処理できるように、tbody要素にアクセスします。 - 最初の行の最初のセルを選択する
「商品一覧」テーブルの最初の行(tr)の最初のセル(td)を選択し、その内部にあるinput要素を取得します。 - そのセルにユーザーが貼り付け(ペースト)した際のイベントを設定する
ユーザーがExcelからデータを最初のセルに貼り付けた(ペーストした)際に、pasteイベントがトリガーされ、処理が実行されるように設定します。 - クリップボードからデータ(Excelからコピーされたデータ)を取得する
ペースト時、ブラウザはクリップボードからデータを提供します。このデータをテキスト形式で取得します。 - データを解析する:行と列に分割する
Excelのデータは通常、タブ(\t)と改行(\n)で区切られたテーブル形式です。このデータを、行と列のリストに分割します。 - 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);
結果

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

