1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GAS勉強会4 ~複数の値をWebアプリからスプレットシートに保存する

Last updated at Posted at 2025-10-13

1.はじめに

以前Webアプリから値を取得し、スプレットシートに保存する方法を学んだ。
GAS勉強会2 ~Webアプリからスプレットシートに値を登録する~

今回はより実用的な方法としてWebアプリに複数の入力欄を作成し、新たなデータとしてスプレットシートに保存する方法を学ぶ。
ついでに、今後データの編集も行うことを想定し、データごとに固有IDとタイムスタンプを付与する。

2. GAS、HTMLの骨格

HTML

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script>

    </script>
  </head>
  <body>
    <h2>商品登録フォーム</h2>
      <form id="product_form">
        <label for="product_name">商品名:</label>
        <input type="text" id="product_name" required><br><br>

        <label for="price">価格:</label>
        <input type="number" id="price" required><br><br>

        <button type="button" onclick="submitForm()">登録</button>
      </form>

  </body>
</html>

GAS

const ss = SpreadsheetApp.openById("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
const sheet = ss.getSheetByName("シート1");

function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}

今回は「商品名」と「価格」を入力し登録することにする。

3.GASのプログラムを完成させる

GASのプログラムに以下の関数を追加する。

function addProduct(products) {

  const lastRow = sheet.getLastRow();

  // IDの一覧を作る。Set で作ると処理早くなるらしい。
  // Math.maxを使うことで0行目を参照するリスクをなくす。
  const existingIds = new Set(sheet.getRange(2, 1, Math.max(1, lastRow - 1), 1).getValues().flat()); 
  // console.log(Array.from(existingIds));

  const newId = generateUniqueId(existingIds);

  const timestamp = new Date().getTime();
  
  sheet.appendRow([newId, timestamp, products.productName, products.price]);

  return "success";
}

function generateUniqueId(existingIds) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

  let id;
  do {
    id = Array.from({ length: 8 }, () => 
      chars[Math.floor(Math.random() * chars.length)]
    ).join('');
  } while (existingIds.has(id)); //重複してたら再生成
  return id;
}

addProducts関数でHTMLから値を取得し、スプレットシートに保存する仕組みを作っている。
existingIdsに既に作成されているID一覧を保存する。Math.max(1, lastRow - 1)とすることでスプレットシートにデータがない場合に0行目(存在しない)の値を取得しようとすることを防ぐ。
new Setとすることで処理が速くなるらしい。知らんけど。

generateUniqueId(existingIds)で新しいIDを作成する。この関数の中身は後で説明する。
new Date().getTime()で現在時刻を取得する。.getTime()にすることでタイムスタンプにする。new Date()のデータのままではブラウザに日付データを送るときにエラー吐くのでタイムスタンプに変換している。

 sheet.appendRow([newId, timestamp, products.productName, products.price]);

ID、タイムスタンプを含めた値を保存する。
※HTMLからはオブジェクト形式でデータを送られていることに注意。

function generateUniqueId(existingIds) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

let id;
do {
  id = Array.from({ length: 8 }, () => 
    chars[Math.floor(Math.random() * chars.length)]
  ).join('');
} while (existingIds.has(id)); //重複してたら再生成
return id;
}

ここの関数では新たなIDを作成するが、条件として
 1.英数字36文字からランダムに8桁のIDを作成する。
 2.過去に既に使用されているIDであれば新規IDを作り直す。
としている。
do{}の中身が実際のプログラム部分。
Array.fromではまず長さ8の空の配列を作り、() => chars[Math.floor(Math.random() * chars.length)]で各要素ごとにランダムな文字列を選ぶ。
chars.length ⇒ 36
Math.random() * 36 ⇒ 0~35の乱数を生み出す。
Math.floorで小数点以下切り捨て。
つまり、

chars[Math.floor(Math.random() * chars.length)]

は[]内で0~35のランダムな整数を生成し、生成された値に該当する文字をcharsから取得している。
.join('')で配列を文字列に連結する。
(例:["A", "B", "3", "X", "Z", "9", "T", "1"]"AB3XZ9T1"
while (existingIds.has(id));

4.HTMLの処理を完成させる

HTMLの<script>に以下を記述する。

      // フォームの送信処理
      function submitForm() {
        const productName = document.getElementById("product_name").value;
        const price = document.getElementById("price").value;

        if (!productName || !price) {
          alert("必須項目を入力してください。");
          return;
        }

        google.script.run
          .withSuccessHandler(() => {
            alert("商品を登録しました>");
            document.getElementById(product_form).reset();
          })
          .withFailureHandler((err) => {
            alert("エラー:" + err.message);
          })
          .addProduct({ productName, price });
      }

      // inoputに対するEnterキー操作を監視
      window.onload = function () {
        document.querySelectorAll("input").forEach(input => {
          input.addEventListener("keydown", preventEnterSubmit);
        });
      };

      // Enterキーで送信させない処理
      function preventEnterSubmit(event) {
        if (event.key === "Enter") {
          event.preventDefault(); // デフォルトの送信動作を無効化
          const inputs = Array.from(document.querySelectorAll("input"));
          const index = inputs.indexOf(event.target);
          if (index > -1 && index < inputs.length - 1) {
            inputs[index + 1].focus(); //次の入力欄へ移動
          }
        }
      }

submitForm()の説明

productNameprice変数を定義して入力された値を保存する。
if文で空白の入力欄があればエラーを吐くようにする。

google.script.runでサーバーにデータを送り結果の処理をする。
.addProduct({ productName, price });としてオブジェクト型でサーバーへ送る。

おまけのプログラム

window.onload = function () {preventEnterSubmit(event)関数はおまけとして作ってみた。
上の入力欄を記入し終わると、エンターキーを押したら次の入力欄に行くようにしている。
ただし、最後の入力欄に記入した後はエンターキーを押しても何も起こらず、ボタンを押した場合のみ送信処理が行われるように調整している。

document.querySelectorAll("input").forEach(input => {ですべての入力欄を監視する。
input.addEventListener("keydown", preventEnterSubmit);では入力欄で何かキーが押されたらpreventEnterSubmit関数を呼び出している。
if (event.key === "Enter") {で押されたキーがエンターキーの場合のみを扱うようにしている。
event.preventDefault();はデフォルトではエンターキー入力で送信処理が行われてしまうのを夢告化している。
Array.from(document.querySelectorAll("input"));<input>要素を配列に変換末う。
inputs.indexOf(event.target);では<inout>要素の中の何番目でエンターキーが押されたか確認する。

          if (index > -1 && index < inputs.length - 1) {
            inputs[index + 1].focus(); //次の入力欄へ移動

では一番下の入力欄でエンターキーを押されたかを確認し、一番下の入力欄でない限り次の入力欄へ移動する処理をしている。

5.まとめ

以上で複数のデータをスプレットシートに登録することができた。(なんか話がすごく脱線していたような…)

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?