背景
GAS初心者がWebフォームをGASで自作し、入力後の送信後画面を出そうとしただけで、それは大変な時間を費やしたのでした。
たくさんサンプルはあるんですけど、いい感じに組み合わせた例は無い気がしたので、まとめてみました。
その1. Googleフォームじゃちょっと足りないんだよね...
Googleフォームを使えば、簡単にアンケートや集計をとれます。
でも、ちょっと複雑なバリデーションチェック(入力チェック)はできなかったりと、壁を感じていました。
それでGASでwebフォームを作ったんですが、フォームデータ送信時に2点大きな問題が発生してしまいました。
- ボタンを連打すると複数回データが送信されてしまう
- 入力直後のページのままブラウザを閉じたあとに、再度ブラウザを開くと送信後の画面を開いてしまい、データを再送してしまう
その2. そんなにJavaScript得意じゃないんだよね...
必要に迫られてその都度調べながら、切り貼りして「これでいいんだよね?」的な感じでGAS, JavaScriptのプログラミングをしていると、複数ページのWebサイトを作るのは結構大変でした。
そんなに人の参考になればいいな、と思います。
最初の状態:GASで複数ページを作る
こちらのページを参考に、複数ページからなるwebフォームを作りました。
この時点で最初はかなり満足していたんですけど。
GAS(HtmlService)で複数のページを遷移(SPA)
改善後の状態:GASで複数ページ + 送信完了ページへ自動遷移
ごく簡単なWebフォームです。
名前を入力し、送信ボタンを押すと、送信中画面、送信完了画面と自動で画面が遷移します。
このフォームを入力すると、こんな感じにスプレッドシートに保存されていきます。
プログラム
GASエディタで以下を入力し、デプロイしてください。
// コード.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 -->
<!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のブログの一つとして書きました。
参加した皆さん、お疲れ様です!