安全なデータ登録とSPA風完了画面:ユニークID採番とフォームリセットの実装

全5回にわたるWebフォーム開発シリーズの最終回です。

前回は、フロントエンドでの丁寧な入力チェックと「その他」自由入力欄の連動制御を実装しました。

今回は、整えられたデータを受け取ってスプレッドシートへ安全に書き込むGASバックエンド関数と、画面をリロードせずに完了メッセージへ切り替えるシングルページアプリケーション(SPA)スタイルのUI設計を解説します。

サーバー側での安全なデータ追記とリロード不要の完了画面切り替え

サーバー側での安全なデータ追記とリロード不要の完了画面切り替え

一意な管理番号を採番する generateUniqueId 関数

フォームから送信されたデータをスプレッドシートで管理する際、連番の数字(1, 2, 3…)に頼ると、途中の行を削除した際に番号の不整合が生じたり、問い合わせ窓口で照合しづらくなったりします。
英小文字と数字を組み合わせた8桁のランダムIDを生成して付与します。

// 8桁の英数ランダムIDを生成
function generateUniqueId() {
  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';
  for (let i = 0; i < 8; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return result;
}

重複リスクが極めて低く、ユーザーへの受付番号としてもスマートに提示できる管理コードを即座に生成できます。

スプレッドシートへの保存を担う submitForm 関数

ブラウザから送られてきたデータオブジェクトを受け取り、「受付台帳」シートの末尾に追記する関数です。

function submitForm(data) {
  try {
    // サーバーサイドでの多重バリデーション
    const required = ['fullName', 'email', 'phone'];
    for (const k of required) {
      if (!data[k] || String(data[k]).trim() === '') {
        throw new Error(`必須項目が未入力です: ${k}`);
      }
    }

    const now = new Date();
    // 日本時間の統一書式で日時文字列を作成
    const registrationDate = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy/MM/dd');
    const updateDateTime  = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss');
    const uniqueId = generateUniqueId();

    const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
    const sh = ss.getSheetByName(SHEET_NAME);

    // 行データを追加(配列項目はカンマ区切り文字列に変換)
    sh.appendRow([
      uniqueId,
      data.fullName || '',
      data.email || '',
      data.phone || '',
      Array.isArray(data.category) ? data.category.join(', ') : (data.category || ''),
      Array.isArray(data.service) ? data.service.join(', ') : (data.service || ''),
      data.memo || '',
      registrationDate,
      updateDateTime,
      'フォーム送信'
    ]);

    return { ok: true, message: '登録が完了しました。ありがとうございました。' };
  } catch (err) {
    return { ok: false, message: String(err) };
  }
}
重要ポイント 役割と効果
多重バリデーション フロントエンドをすり抜けた不正リクエストをサーバー側で確実に遮断し、不備のあるデータがシートに混入するのを防ぎます。
Utilities.formatDate タイムゾーン(Asia/Tokyo)を指定して日時を整形することで、実行環境によるタイムゾーンのブレを排除します。
appendRow による追記 末尾行に安全に1行を追加します。セルの直接指定と異なり、同時書き込み時の衝突や上書き事故を防止します。

画面遷移のないSPA風の完了画面切り替え

一般的なWebフォームでは送信後に「thanks.html」などの別URLへ遷移しますが、GASのWebアプリでリダイレクトを行うと画面の再読み込みに数秒かかってしまいます。
同一ページ内でDOMの表示・非表示を切り替えることで、瞬時に心地よい完了画面を提示できます。

google.script.run
  .withSuccessHandler(function(result) {
    if (result.ok) {
      // フォームを非表示にして成功メッセージを表示
      document.getElementById('form-container').style.display = 'none';
      document.getElementById('success-message').style.display = 'block';
    } else {
      msg.textContent = 'エラー: ' + result.message;
      btn.disabled = false;
    }
  })
  .withFailureHandler(function(error) {
    msg.textContent = 'エラー: ' + error.message;
    btn.disabled = false;
  })
  .submitForm(data);

連続送信に対応する resetForm 関数の実装

展示会や店頭受付など、同じ端末で何人ものユーザーが続けて入力する場合、ページをリロードすることなく初期状態に戻せるリセット機能を用意しておくと便利です。

function resetForm() {
  // 成功メッセージを非表示にしてフォームを再表示
  document.getElementById('success-message').style.display = 'none';
  document.getElementById('form-container').style.display = 'block';
  
  // フォームコントロールの入力値を初期化
  document.getElementById('f').reset();
  
  // エラー表示とステータスメッセージを非表示に
  document.querySelectorAll('.error-message').forEach(function(el) {
    el.style.display = 'none';
  });
  document.getElementById('msg').textContent = '';
  document.getElementById('sendBtn').disabled = false;
  
  // 画面トップへスムーズに移動
  window.scrollTo(0, 0);
}

連載の総括

全5回にわたり、Google Apps Scriptとスプレッドシートをフル活用した高機能Webフォームシステムの仕組みを解説してきました。

  • 第1回:全体アーキテクチャの設計とdoGet関数によるWeb配信
  • 第2回:マスタ設定シートから選択肢を動的に抽出・整形するGASバックエンド処理
  • 第3回:google.script.runを用いた非同期通信とタッチしやすいチェックボックスの生成
  • 第4回:「その他」連動入力制御とエラー箇所への自動スクロール機能
  • 第5回:ユニークID採番による安全なデータ追記とリロード不要の完了画面

これらの仕組みを組み合わせることで、高額な外部ツールに頼ることなく、自社の業務フローにフィットした堅牢で使いやすいWeb受付システムを自由に構築できます。ぜひ日々の業務効率化にお役立てください。


eguchi.netをもっと見る

購読すると最新の投稿がメールで送信されます。