GAS+GoogleSlides+Spreadsheetで投票システムを自作した話

# はじめに
この記事は[LIFULL Advent Calendar 2021](https://qiita.com/advent-calendar/2021/lifull)の12/5と記事になります。
(今書いているのは12/19なので大遅刻です誠にすみません)

# 背景
皆様、生活してるとイケてる投票システムが欲しくなることありませんか？ありますよね？そう、あるんですよ。

少し前に会社内のでプロジェクトアワードという催しを行いました。
社内で行われたプロジェクトへの称賛と全社への情報共有を目的としたもので、エントリーされたプロジェクトに社員に投票してもらう企画です。
ここ数年のPJアワードの投票システムは以下のような形で運用してました。

- PJ資料共有: GoogleSlides
- 投票: GoogleForm

ただこれだとSlidesとFormを行ったり来たりする必要があったのでもうちょいイケてる投票システムが欲しいなあと思うようになりました。

# GoogleSlidesだけで完結する投票システム
投票者の行ったり来たりを防ぐためには、資料と投票が一体になっていればいいんじゃないかという思考です。
以前にGASを使ってスプレッドシートのメニューにアイテム追加したことがあったので、その応用でGASを用いてSlidesとSpreadsheetを結合しました。

- Slides
    - PJ資料の表示
- Spreadsheet
    - 投票結果の格納
- GAS
    - Slides側
        - メニューバーに投票システムのアイテムを表示
        - 投票用UIの実装
    - Spreadsheet側
        - 投票結果をシートの格納

## 具体的な実装
### メニュー
Slidesから投票システムを呼び出します。
メニューにアイテムを追加するのは簡単なのでいろんなケースで使えます。
Spreadsheet上で関数でうまくできない集計や計算をするのに役立ちますが、神Excelならぬ神Spreadsheetがよく生成されます。
開発チームで使用する際はある程度見やすく書いておくと他人にぶん投げやすいもとい引き継ぎしやすいのでおすすめです。
リーダブルに書かないと永遠に主観が自分のシートができます、というかできた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211856/9bc0784c-383a-3dd5-cb57-8e7480c89647.png)

対象のSlidesのメニュー > ツール > スクリプトエディタからGASのコード画面が開くので、↓のように記載するとSlides上からGASの関数を起動できます。

```
function onOpen() {
  SlidesApp.getUi()
      .createMenu('投票システム')
      .addItem('投票する', 'openDialog')
      .addToUi();
}
```

### 投票モダル

上記の「投票する」を選択すると投票用のモダルが表示されます。
投票項目のLQSは弊社における品質基準のLIFULL Quality Standardsを採用しています。
こちらの詳細は[公式HP](https://lifull.com/company/philosophy/), または[公式noteの記事](https://corp.lifull.com/n/n411b697f83f3)を参照ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211856/155c6af6-822d-70d5-4b2f-832a52484a6d.png)
先の投票システムメニューの「投票する」を選択するとGAS上の`openDialog`関数が実行されます。
ここはHTMLファイルをレンダリングしてるだけです。

```
function openDialog() {
  var html = HtmlService.createTemplateFromFile('hoge')
    .evaluate()
    .setWidth(600)
    .setHeight(600)
    .setSandboxMode(HtmlService.SandboxMode.IFRAME);
  SlidesApp.getUi()
      .showModalDialog(html, '投票システム');
}
```

### 投票
ここで厄介だったのが、ここのHTML上でのPOSTをGAS上でPOSTがうまいこと動かないことでした。
結果POSTの動作をjsで止めてGASの関数を呼び出す形を取りました。
formの情報を取得してGAS上の`doSubmit`関数にSpreadsheetに格納する情報を渡してます。
（GASからSpreadsheetを更新する資料は割と充実しているので割愛）
↓のjsコードはHTMLファイルのscriptタグにベタ書きです。

```
  function preventFormSubmit() {
    var forms = document.querySelectorAll('form');
    for (var i = 0; i < forms.length; i++) {
      forms[i].addEventListener('submit', function(event) {
        event.preventDefault();
        if(this.lqs.value === '') {
          return;
        }
        
        vote = {
          projectId: this.projectId.value,
          projectName: this.projectName.value,
          email: this.email.value,
          lqs: this.lqs.value
        }
        google.script.run.withSuccessHandler(success).doSubmit(vote);

        // successMessageは↓のような成功時メッセージを表示するGAS側関数
        // SlidesApp.getUi().alert(text);
        google.script.run.successMessage(vote);
      });
    }
  }
  window.addEventListener('load', preventFormSubmit);
  function success(){
    google.script.host.close();
  }
```

あとはSpreadsheetでよしなに集計するのみです。
これにより、GoogleSlidesから移動することなく投票が行える状態になりました。

# あとがき
Spreadsheet+GASの記事は結構多かったのですが、Slides+GASの記事があまりなかったので書きました。
（今回はSlidesならではの機能は全然使ってませんが）
メニューに組み込むことでGAS関連の画面を全く見ずにGASの恩恵にあやかれるのが素敵です。