corp-engr 情シスSlack(コーポレートエンジニア x 情シス) Advent Calendar 2019の1日目の記事です。
Google Apps Script(以下GAS)でネタを探していたところで、忘年会で使おうとクイズアプリを作ったので紹介します。
コーポレートエンジニアあんまり関係ないかもw
#はじめに
12月に入って本格的に忘年会シーズンですね。
忘年会盛り上げるためにクイズ大会でもしたいな、と思ってKahoot!使おうと思ってたのですが、Free版だと人数やなにやら制限がありそうなので作れないかとやってみました。
結果、似たようなことができそうだったので紹介します。
クイズアプリに限らずこういったウェブアプリが作れるということを知ってもらい、GAS好きがもっと増えてほしいな。
#想定読者
- GASは触ったことあるけどWebアプリは作ったことなく、興味のある方
- 忘年会何するか決めかねている方
#注意点
- GASってなんぞ?という方には少し難しいかもしれません。
- 本記事ではCSSを記述していません。これから。
- 数十人で使った場合ちゃんと動くのか怪しいです。
- 結局、盛り上がるかは司会者次第でしょう。
#ユーザー登録画面
まずはスプレッドシートを開いて、ツール > スクリプトエディタ
でScriptEditorを開きます。
プロジェクト名、コード.gsの名前を適当に変更しましょう。
最初に呼び出すHTMLを作成します。
ファイル > New > HTMLファイル
loginと名前をつけてOK
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form method="post" action="(ウェブアプリケーションのURL)?p=0">
<p><label>ユーザー名を入力してください。</label></p>
<p><input type="text" name="name"></p>
<p><input type="submit" value="ENTER"></p>
</form>
</body>
</html>
(ウェブアプリケーションのURL)
は後ほど説明します。
GASの処理で利用するためURLに?p=0
とパラメータを付与しています。
こうすると、GASでe.parameter['p']
とすることで付与した0
が取得でき、現在のページの判定として使用しています。
0 = login
1 = start
など
HTMLを表示させるためquiz.gs
に書きます。
function doGet(e){
return HtmlService.createHtmlOutputFromFile('login');
}
Google Apps Script Class HtmlService
動作確認のためデプロイしてみましょう。
公開 > ウェブアプリケーションとして導入...
デプロイするとURLが発行されるのでコピーして先ほどのlogin.htmlの(ウェブアプリケーションのURL)
に設定します。
そしてもう一度デプロイしましょう。
HTMLやGASの変更を動作確認する際は都度デプロイする必要があります。毎回です。
変更を適用するデプロイは必ずProject version
をNew
にするのを忘れないようにしてください。
ちなみに何度デプロイしてもウェブアプリケーションのURLは変わりません。
#スタート画面
ユーザー名を入力したらスプレッドシートに記録します。
そしてスタート画面に遷移させたいのでHTMLファイルを追加してください。
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form method="post" action="(ウェブアプリケーションのURL)?p=1">
<p><label><?=name?>さん</label></p>
<input type="hidden" name="name" value=<?=name?>>
<p><label>案内があるまでお待ちください...</label></p>
<p><input type="submit" value="START!!!"></p>
</form>
</body>
</html>
login画面の次に表示される画面になるのでパラメータには?p=1
を設定します。
GASのdoPost
に以下の処理を追記します。
- login.htmlからのパラメータを受け取る
- スプレッドシートにユーザー名を記録
- ユーザー名を付与してstart.htmlを呼び出す
function doPost(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var columnValue = sheet.getRange('A:A').getValues();
var lastRow = columnValue.filter(String).length; //最終行を取得
var pages = [ //全ページを配列で持つ
"login",
"start"
];
var currentPage = pages[e.parameter["p"]]; //URLに付与したパラメータ(?p=0)から現在のページを取得
var nextPage = pages[parseInt(e.parameter["p"], 10) + 1]; //次のページを取得
if (currentPage === "login") {
sheet.appendRow([lastRow, e.parameter.name]); //ユーザー名をスプレッドシートに追加
}
var tpl = HtmlService.createTemplateFromFile(nextPage);
tpl.name = e.parameter.name;
return tpl.evaluate();
}
デプロイするとスプレッドシートへのアクセス承認が必要になりますので指示に従って承認します。
終わったらlogin画面でtest
と入力してENTER
をクリックして確認してみましょう。
#あとは複製するだけ
ここまで理解できればあとは複製してクイズ画面を作っていきます。
quiz1.html
を作り、複製してquiz2.html
quiz3.html
とクイズの終わりに表示するend.html
ファイルを作成しそれぞれHTMLを記述します。
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form method="post" action="(ウェブアプリケーションのURL)?p=2">
<p><label><?=name?>さん</label></p>
<input type="hidden" name="name" value=<?=name?>>
<p><label>第 1 問</label></p>
<p><label>Twitterで、一度に投稿できるテキストの文字数は最大何文字?</label></p>
<p><input type="submit" name="quiz" value="120文字"></p>
<p><input type="submit" name="quiz" value="140文字"></p>
<p><input type="submit" name="quiz" value="160文字"></p>
<p><input type="submit" name="quiz" value="180文字"></p>
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form method="post" action="(ウェブアプリケーションのURL)?p=5">
<p><label><?=name?>さん</label></p>
<input type="hidden" name="name" value=<?=name?>>
<p><label>お疲れ様でした〜!</label></p>
</form>
</body>
</html>
そして最終的なquiz.gs
はこんな感じです。
function doGet(e){
return HtmlService.createHtmlOutputFromFile('login');
}
function doPost(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var columnValue = sheet.getRange('A:A').getValues();
var lastRow = columnValue.filter(String).length;
var pages = [
"login",
"start",
"quiz1",
"quiz2",
"quiz3",
"end"
];
var currentPage = pages[e.parameter["p"]];
var nextPage = pages[parseInt(e.parameter["p"], 10) + 1];
var tpl = HtmlService.createTemplateFromFile(nextPage);
if (currentPage === "login") {
sheet.appendRow([lastRow, e.parameter.name]);
}
if(currentPage.indexOf("quiz") === 0){
//quizの場合は回答を記録
answer(sheet, lastRow, e.parameter.name, e.parameter.quiz, parseInt(e.parameter["p"]) + 1)
}
tpl.name = e.parameter.name;
return tpl.evaluate();
}
function answer(sheet, row, user, answer, column) {
var users = sheet.getRange(1,2,row).getValues();
for(var i = 0; i < users.length; i++) {
if (users[i] == user) {
sheet.getRange(i + 1, column).setValue(answer);
}
}
}
#これからやること
- CSS
- 結果やランキングがわかるようにする
#最後に
とりあえず作ってみようって感じで調べつつ、動かしつつ進めたのですが、なんだかんだであとデザインちゃんとしたら普通に使えそうだなって思いました。
スプレッドシートへの書き込みとか大人数で期待通り動くかは少し心配。
あと問題文はプロジェクターで投影して、回答のみ手元のアプリでやってもらう方がいいんじゃ...?
#参考記事
GoogleAppsScript(GAS)でページ遷移を擬似的に実装する方法
Google Apps Scriptで簡単にWebアプリケーションを公開する方法
Google Apps ScriptでWebアプリケーションを作る最初の一歩 HtmlServiceオブジェクトとは
htmlとgoogle apps script間の値の引渡しについて
GASでGetパラメータを受け取ってスプレッドシートに書き込む方法
GASでWebページを作るときにHTMLとCSSを別ファイルに記述する方法
コピペでできる!cssとhtmlのみでフォームのテキストエリアをわかりやすくするデザイン15選