Excelのデータをセルごとに分割してフォームにコピペする【JavaScript】

JavaScript

タイトルそのままですが、Excelのデータをフォームにコピペしたら、セルごとに分割してペーストされる動きをJavaScriptで実装したのでメモ。

セルごとに分割してフォームにコピペする動作を確認する(デモ)

例えば、次のようなエクセルのデータをコピペすると、セルごとに分割してペーストされます。

Input要素がすべてクリアされるボタンも追加しました。

実際の動きはサンプルでご確認ください!

See the Pen input-table by donguri2020 (@m-ke) on CodePen.

検証用のExcelデータがない場合、貼り付け用のテキストを準備したので、次のようにコピペして動きを確認できます。

コード(全体)

HTML

HTMLはシンプルにDIVタグだけを用意し、#input_wrapというID名をつけておきます。
#input_wrapにInputタグを動的に追加するので、子要素は入れないようにします。
クリアボタンが必要でしたら次のように#clear_btnというIDでボタンを追加します。

<!-- クリアボタン  -->
<button id="clear_btn">クリア</button>

<div id="input_wrap">
  <!-- ここにInput要素を作成 -->
</div>

JavaScript
こちらがJavaScript全体のコードです。

const inputWrap = document.querySelector('#input_wrap');
const clearBtn = document.querySelector('#clear_btn');

window.addEventListener('DOMContentLoaded', function(){
  // input要素を作成する
  InputFactory(60, 4, inputWrap);
});

// input要素を作成
function InputFactory(row, col, parentNode) {
  for (let i = 0; i < row; i++) {
    const createDiv = document.createElement('div');
    for (let j = 0; j < col; j++) {
      const createInput = document.createElement('input');
      createInput.type = 'text';
      createInput.name = `input${i}-${j}`;
      createDiv.appendChild(createInput);
      const pastInput = new PastInput(createInput);
    }
    parentNode.appendChild(createDiv);
  }
}

// ペーストした時の処理
class PastInput {
  constructor(target) {
    this.target = target;
    this.event();
  }
  event() {
    this._getInputRowCol();
  }
  // ペーストした時のInputの位置(rowとcol)を取得
  _getInputRowCol() {
    const target = this.target;
    // ペーストイベント
    target.addEventListener('paste', (e) => {
      // ターゲット要素(input)
      const targetInput = e.target;
      // 全てのDIV要素取得
      const divAll = inputWrap.querySelectorAll('div');
      console.log(divAll)
      // 全てのInput要素取得
      const inputAll = inputWrap.querySelectorAll('input');
      // ターゲットの親要素(DIV)取得
      const targetDiv = targetInput.parentNode;

      // 全てのDiv要素取得をArrayに変換
      const divAllAry = Array.from(divAll);
      // 全てのInput要素取得をArrayに変換
      const inputAllAry = Array.from(inputAll);

      // ターゲット要素のrowとcolインデックスを取得
      const rowIndex = divAllAry.indexOf(targetDiv);
      const colIndex =
        inputAllAry.indexOf(targetInput) % targetDiv.children.length;

      // ペーストした値をInput要素に反映
      this._textPaste(rowIndex, colIndex);
      console.log(rowIndex, colIndex)
    });
  }
  _textPaste(row, col) {
    // ペーストしたInput要素を取得
    const target = this.target;

    setTimeout(() => {
      // ペーストしたInput要素のテキスト取得
      const pasteText = target.value;
      // ペーストしたInput要素のテキストを配列に変換
      const pasteAry = pasteText.split(' ');

      // テキストをそれぞれのInput要素に分割して反映
      pasteAry.forEach((pastItem, index) => {

        const currentDiv = inputWrap.children[row + index];
        console.log(inputWrap.children)
        const resultItem = pastItem.split(/\t/);

        // Input要素があればテキストを反映
        if (currentDiv !== undefined) {
          for (let i = 0; i < resultItem.length; i++) {
            const currentInput = currentDiv.children[col + i];
            if (currentInput !== undefined) {
              currentInput.value = resultItem[i];
              // 背景色追加のCSS追加
              currentInput.classList.add('starting-point');
               // 背景色追加のCSS削除
              setTimeout(() => {
                currentInput.classList.remove('starting-point');
              }, 500);
            }
          }
        }
      });
    });
  }
}

// データを全てクリアする
clearBtn.addEventListener('click', (e) => {
  const inputAll = inputWrap.querySelectorAll('input');
  // 全てのInput要素をArrayに変換
  const inputAllAry = Array.from(inputAll);
  for (let i = 0; i < inputAllAry.length; i++) {
    const targetInput = inputAllAry[i];
    targetInput.value = '';
  }
});

Input要素をいくつ生成するか設定する

コードをコピペすれば動くと思いますが、Input要素を生成する際の個数を設定できるようにしました。
以下の関数で生成しています。

InputFactory(<縦の個数>, <横の個数>, <生成する要素>);

引数に、縦と横に並べるInput要素の数と、Input要素を生成する親要素を指定します。
今回Input要素を生成する親要素は、#input_wrapです。

以下のコードは、#input_wrapに縦60個、横4つのInput要素を生成します。
※関係のある箇所だけを抜粋しました。

<div id="input_wrap">
<!-- ここにInput要素を作成 -->
</div>

<script>
  const inputWrap = document.querySelector('#input_wrap');

  window.addEventListener('DOMContentLoaded', function(){
    // input要素を作成する
    InputFactory(60, 4, inputWrap);
  });
</script>

まとめ

このコードを使用する際の注意事項ですが、Excelのセルの値に半角スペースが入らないことが前提となっています。

というのも、複数のセルをコピーすると、セル同士の間に半角スペースが入るからです。

Excelからコピーした値をInput要素に分割して貼り付ける際、この半角スペースを判定の基準としています。そのため、データに半角スペースが入っている場合、うまく機能しません、、。

そもそもコピペするデータ量が多ければ、素直にCSVファイルなどを読み込んだ方が良いかもしれません。

とりあえず動く機能がつくれたのでメモしておきます!