0
0

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で送信中画面のあるwebフォームを作る

Posted at

背景

GAS初心者がWebフォームをGASで自作し、入力後の送信後画面を出そうとしただけで、それは大変な時間を費やしたのでした。
たくさんサンプルはあるんですけど、いい感じに組み合わせた例は無い気がしたので、まとめてみました。

その1. Googleフォームじゃちょっと足りないんだよね...

Googleフォームを使えば、簡単にアンケートや集計をとれます。
でも、ちょっと複雑なバリデーションチェック(入力チェック)はできなかったりと、壁を感じていました。

それでGASでwebフォームを作ったんですが、フォームデータ送信時に2点大きな問題が発生してしまいました。

  • ボタンを連打すると複数回データが送信されてしまう
  • 入力直後のページのままブラウザを閉じたあとに、再度ブラウザを開くと送信後の画面を開いてしまい、データを再送してしまう

その2. そんなにJavaScript得意じゃないんだよね...

必要に迫られてその都度調べながら、切り貼りして「これでいいんだよね?」的な感じでGAS, JavaScriptのプログラミングをしていると、複数ページのWebサイトを作るのは結構大変でした。
そんなに人の参考になればいいな、と思います。

最初の状態:GASで複数ページを作る

こちらのページを参考に、複数ページからなるwebフォームを作りました。
この時点で最初はかなり満足していたんですけど。

GAS(HtmlService)で複数のページを遷移(SPA)

改善後の状態:GASで複数ページ + 送信完了ページへ自動遷移

ごく簡単なWebフォームです。
名前を入力し、送信ボタンを押すと、送信中画面、送信完了画面と自動で画面が遷移します。

webフォーム.png

送信中.png

送信完了.png

このフォームを入力すると、こんな感じにスプレッドシートに保存されていきます。

入力後スプレッドシート.png

プログラム

GASエディタで以下を入力し、デプロイしてください。

code.gs
// コード.gs
function doGet() {
  return HtmlService.createTemplateFromFile("index").evaluate();
}

function saveName(name) {
  const sheetId = 'スプレッドシートID'; // ここにスプレッドシートのIDを入力
  const sheet = SpreadsheetApp.openById(sheetId).getActiveSheet();
  sheet.appendRow([name]); // 名前をスプレッドシートの最終行に追加
}
index.html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <style>
    .loading {
      display: none;
      text-align: center; /* 中央揃え */
      margin-top: 50px;
    }
    
    .loader {
      border: 16px solid #f3f3f3; /* 薄い色のボーダー */
      border-top: 16px solid #3498db; /* 上部のボーダーの色 */
      border-radius: 50%; /* 円形にする */
      width: 50px; /* 幅 */
      height: 50px; /* 高さ */
      animation: spin 2s linear infinite; /* アニメーションを設定 */
      margin: 0 auto; /* 中央揃え */
    }

    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }

    .page:not(.isActive) {
      display: none;
    }
  </style>
  <script>
    function submitForm() {
      const nameInput = document.querySelector('input[type="text"]').value; // 名前を取得
      document.getElementById("loader").style.display = "block"; // 処理中のグルグルを表示

      google.script.run.withSuccessHandler(function() {
        document.getElementById("loader").style.display = "none"; // ②処理中画面を非表示
        switchPage('success'); // ③送信完了画面に遷移
      }).saveName(nameInput); // ①名前を保存する関数を呼び出す
    }

    function switchPage(pageName) {
      const pages = Array.from(document.getElementsByClassName("page"));
      for (const page of pages) {
        if (page.id === pageName) {
          page.classList.add("isActive");
        } else {
          page.classList.remove("isActive");
        }
      }
    }

    document.addEventListener("DOMContentLoaded", (event) => {
      // 初期表示
      switchPage("home");
    });
  </script>
</head>
<body>
  <div id="loader" class="loading">
    <div class="loader"></div> <!-- グルグル回る要素 -->
    <div>処理中...</div> <!-- 処理中のテキスト -->
  </div>
  
  <!-- ページ切り替え -->
  <div id="home" class="page isActive">
    <h1>ホームページ</h1>
    <form onsubmit="event.preventDefault(); submitForm();">
      <input type="text" placeholder="名前" required>
      <button type="submit">送信</button>
    </form>
    <a href="#" onclick="switchPage('contact');">お問い合わせ</a>
  </div>

  <div id="success" class="page">
    <h1>送信完了</h1>
    <p>フォームが正常に送信されました!</p>
    <a href="#" onclick="switchPage('home');">戻る</a>
  </div>

  <div id="contact" class="page">
    <h1>お問い合わせ</h1>
    <p>お問い合わせ内容はこちらに入力してください。</p>
    <a href="#" onclick="switchPage('home');">戻る</a>
  </div>
</body>
</html>

まとめ

ここで紹介した例が最適とはとても思えないんですが、誰かの参考になれば嬉しいです。

なお、この記事は、【札幌現地+オンライン開催】力強くブログを108記事アウトプットする日の 20241229のブログの一つとして書きました。
参加した皆さん、お疲れ様です!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?