Googleフォームで擬似的に動的なデフォルト値を設定する

# この記事のまとめ
- Googleフォームではデフォルト回答を動的に（今日の日付など）設定できない
- 回答送信時、回答を記録するスプレッドシートに自動で追記することで、擬似的にデフォルト回答を自動入力する機能を実装する
- 本記事では、「今日の日付の自動入力」「別の質問への回答のコピー」の実装をしています。

# はじめに
Googleフォームは簡単にアンケートや予約システムを作成できて便利なサービスですが、かゆいところに手が届かないような場合もあります。
個人的に気になる部分は、デフォルト回答の設定が不十分な点です。一応、「事前入力したURLを取得」することで、事前に回答が設定されたフォームを作成することはできます（[参考リンク](https://qiita.com/jooji/items/79496f65f1c6c18664f5)）。
一方で困るのは、この事前入力の内容を動的に変更したい場合です。たとえば日付など、「いろんな日付を入力する可能性があるけど、いちばんよく入力するのは今日の日付だから、デフォルト値は今日の日付にしたいな」といった場合に、上述の「事前入力したURLを取得」ではあくまで「事前入力した」値を利用することしかできないので、「今日の日付」のような設定はできません。
他にも、たとえば他の選択肢の回答によっては回答の必要がない（回答がなくても埋められる）場合など、動的に値を適用することはできません。

そこで今回は、回答を保存するスプレッドシート側で操作を行うことによって、擬似的に動的なデフォルト回答を利用する方法を紹介します。

# 目指すこと
今回の実装では、「フォームが特定の状態で送信されたときに、スプレッドシートに記録された回答を動的に変更する」ことを目指します。そのため、下記のような注意点があります。
#### 注意点
- フォームの回答画面が動的に変化するわけではない
    - 回答者が回答中に自動的に回答が入力されたりするわけではありません。
- フォームの「回答」欄にはデフォルト値は反映されない
    - 回答送信後に回答が記録されたスプレッドシートを編集する性質上、デフォルト値が反映されるのはフォームの送信後なので、フォーム自体の「回答」欄には反映されません。

# 実装
### 1. フォームの説明
今回は次のようなアンケートフォームを考えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/34e63502-2f69-873d-91b1-3194cdf86cc0.png)
ここで、一部の選択肢についてはこのように考えられます。
- 来店日：
    - 来店日は回答日と同じである可能性が高いので、デフォルト値をその日の日付にしたい
- プレゼント配送先住所：
    - 上の「住所」と同じ可能性が高いので、デフォルト値を上の住所と同じにしたい

そこで、このような機能を実装することを考えます。
- 来店日が空白の場合、その日の日付を自動で補完する
- 配送先住所が空白の場合、住所の値で補完する

このような機能を実装してみましょう。
### 2. スプレッドシートの準備
フォームの編集画面の「回答」欄から、スプレッドシートにリンクしてください。新規作成するか既存のシートに紐付けするか聞かれますが、どちらでも構いません。
これによって、回答が記録されるスプレッドシートが作成（もしくは既存のシートに紐付け）されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/90bcce36-6ef1-e77a-2ff0-cf5fff53c3c0.png)
### 3. Google Apps Script（GAS）エディタの起動
画面上部の拡張機能＞Apps Scriptから、GASのエディタを起動します。
このGASは、Googleのサービスを操作できるプログラミング言語だと思ってもらえれば大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/4f507a55-4f24-0ed3-b317-3e5e52856639.png)
起動ができると、次のような画面が表示されます。ここにプログラムを書いていきましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/bb46d24a-0393-5222-10f6-ee8745d5d845.png)
### 4. コードの記述
たとえば今回はこのようなコードを作成しました（詳しい説明・応用の仕方は後ほど説明します）。
```JavaScript
function onSubmit(){
  // アタッチされているスプレッドシート（＝フォームの回答が記録されるスプレッドシート）を取得
  const ss = SpreadsheetApp.getActiveSpreadsheet()
  // フォームの回答を記録しているスプレッドシートを取得
  const sheet = ss.getSheetByName("フォームの回答 1")
  // 最後の行（＝回答が保存されている行）の行番号を取得
  const row = sheet.getLastRow()
  /*====================ここからデフォルト値を記載するプログラム====================*/
  // 2列目（＝来店日が記載される列）が空白だったら、日付に今日の日付を入力するプログラム
  var targetColumn = 2 // ←ここの数字を目的の列番号に書き換える
  if (sheet.getRange(row,targetColumn).getValue()===''){
    // 今日の日付を取得して
    const today = new Date();
    const date = Utilities.formatDate(today, 'Asia/Tokyo' , 'yyyy/MM/dd')
    sheet.getRange(row,targetColumn).setValue(date)
  }
  // 6列目（＝プレゼント配送先住所が記載される列）が空白だったら、5列目（＝住所が記載される列）の値をコピーする
  var sourceColumn = 5 // ←ここの数字をコピー元の列番号に書き換える
  var targetColumn = 6 // ←ここの数字をコピー先の列番号に書き換える
  if (sheet.getRange(row,targetColumn).getValue()===''){
    sheet.getRange(row,targetColumn).setValue(sheet.getRange(row,sourceColumn).getValue())
  }
}
```
これをそのままエディタに入力しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/a6302a1f-c0d9-bffb-6a26-2b75c25114ea.png)
エディタに入力できたら、一度実行をしておきます（権限の確認をするため）。画面上部の「▷実行」をクリックし、画面に出てくる権限関係の指示に従って、承認してください（[参考ページ](https://qiita.com/STSHISHO/items/f2ce468ab78682c26699)）。

### 5. トリガーの設定
権限の確認ができたら、トリガーを設定していきます。
左側の目覚まし時計マークをクリックし、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/4af9b8c3-245e-7ba5-dc96-4b26f182ba2b.png)
右下の「トリガーを追加」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/8e8e5855-362c-0c3f-5330-743e6b0bfa5f.png)
すると設定画面が現れるので、次のように設定して「保存」してください。保存する際に権限を求められたら、先ほどと同様の方法で承認してください。
これによって、先ほど作成したGoogleフォームが送信されたら自動的に上記のスクリプトが動作するようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/19e47999-7bd9-3985-48a6-b43edd4f2b83.png)

### 6. 動作確認
ためしに、「来店日」「プレゼント配送先住所」を空白にしたままフォームを送信してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/b36b3eb4-4a37-e8fc-0333-2cc8a321ec9d.png)
回答が保存されるスプレッドシートを確認すると、きちんと内容が補完されていることが確認できました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/2ff3395d-1ce5-cfe9-f18b-a42550924fad.png)

ここにフォームと回答を置いておくので、ご自由にお試しください（**回答は公開されてしまうので、絶対に個人情報は入力しないでください**）。
[フォーム](https://docs.google.com/forms/d/e/1FAIpQLSdUe7Gtkx0yk4G1df36mwHHNwFSzBNqtyQuE0f8UzgBhqI4_w/viewform)
[回答スプレッドシート](https://docs.google.com/spreadsheets/d/1ucLDu0uPJx5a5Sk2UoJ5nS4J7s7w3RmC62mNhES9370/edit?usp=sharing)

これで、擬似的にデフォルト値を利用したGoogleフォームを作成することができました。

# プログラムの説明と応用
ここからは、GAS初心者の方向けに簡単にプログラムの説明・どこを変更すれば別のフォームでも利用できるかを説明していきます。まず、プログラム全体は下記のようなものでした。
```JavaScript
function onSubmit(){
  // アタッチされているスプレッドシート（＝フォームの回答が記録されるスプレッドシート）を取得
  const ss = SpreadsheetApp.getActiveSpreadsheet()
  // フォームの回答を記録しているスプレッドシートを取得
  const sheet = ss.getSheetByName("フォームの回答 1")
  // 最後の行（＝回答が保存されている行）の行番号を取得
  const row = sheet.getLastRow()
  /*====================ここからデフォルト値を記載するプログラム====================*/
  // 2列目（＝来店日が記載される列）が空白だったら、日付に今日の日付を入力するプログラム
  var targetColumn = 2 // ←ここの数字を目的の列番号に書き換える
  if (sheet.getRange(row,targetColumn).getValue()===''){
    // 今日の日付を取得して
    const today = new Date();
    const date = Utilities.formatDate(today, 'Asia/Tokyo' , 'yyyy/MM/dd')
    // 書き込む
    sheet.getRange(row,targetColumn).setValue(date)
  }
  // 6列目（＝プレゼント配送先住所が記載される列）が空白だったら、5列目（＝住所が記載される列）の値をコピーする
  var sourceColumn = 5 // ←ここの数字をコピー元の列番号に書き換える
  var targetColumn = 6 // ←ここの数字をコピー先の列番号に書き換える
  if (sheet.getRange(row,targetColumn).getValue()===''){
    sheet.getRange(row,targetColumn).setValue(sheet.getRange(row,sourceColumn).getValue())
  }
}
```
このプログラムは、大きく3つの部分から構成されています。
### 1. 骨格部
プログラムの骨格とも言うべき部分です。ここは必ず書く必要があります。最後の括弧も忘れずに！
この中に、デフォルト値を記入するプログラムを記載していきます。
```JavaScript
function onSubmit(){
  // アタッチされているスプレッドシート（＝フォームの回答が記録されるスプレッドシート）を取得
  const ss = SpreadsheetApp.getActiveSpreadsheet()
  // フォームの回答を記録しているスプレッドシートを取得
  const sheet = ss.getSheetByName("フォームの回答 1")
  // 最後の行（＝回答が保存されている行）の行番号を取得
  const row = sheet.getLastRow()
  /*====================ここからデフォルト値を記載するプログラム====================*/




  /*====================ここまでデフォルト値を記載するプログラム====================*/
}
```
### 2. 日付を補完するプログラム
特定の回答が空白のときに、その欄に今日の日付を入力するプログラムです。
今回は、「来店日」の回答を補完するために使われています。今回「来店日」はスプレッドシートの2列目に保存されるので、`// ←ここの数字を目的の列番号に書き換える`という部分には`2`が記入されていますが、この数字を書き換えることで他の列番号にも対応できます。シートのどの位置に回答が記入されるかによって変更してください。
このプログラムを、1の骨格部の中にコピペすることで、日付を補完できます。
```JavaScript
    // 2列目（＝来店日が記載される列）が空白だったら、日付に今日の日付を入力するプログラム
    var targetColumn = 2 // ←ここの数字を目的の列番号に書き換える
    if (sheet.getRange(row,targetColumn).getValue()===''){
        // 今日の日付を取得して
        const today = new Date();
        const date = Utilities.formatDate(today, 'Asia/Tokyo' , 'yyyy/MM/dd')
        // 書き込む
        sheet.getRange(row,targetColumn).setValue(date)
    }
```
### 3. 別の回答をコピーするプログラム
特定の回答が空白のときに、その欄に別の回答をコピーするプログラムです。
今回は、「プレゼント配送先住所」の回答を補完するために使われています。今回、コピー元の「住所」はスプレッドシートの5列目、「プレゼント配送先住所」はスプレッドシートの6列目に保存されるので、`// ←ここの数字をコピー元の列番号に書き換える`、`// ←ここの数字をコピー先の列番号に書き換える`という部分には`5`と`6`が記入されていますが、この数字を書き換えることで他の列番号にも対応できます。シートのどの位置に回答が記入されるかによって変更してください。
このプログラムを、1の骨格部の中にコピペすることで、回答のコピーによる補完ができます。
```JavaScript
    // 6列目（＝プレゼント配送先住所が記載される列）が空白だったら、5列目（＝住所が記載される列）の値をコピーする
    var sourceColumn = 5 // ←ここの数字をコピー元の列番号に書き換える
    var targetColumn = 6 // ←ここの数字をコピー先の列番号に書き換える
    if (sheet.getRange(row,targetColumn).getValue()===''){
      sheet.getRange(row,targetColumn).setValue(sheet.getRange(row,sourceColumn).getValue())
    }
```

# おわりに
今回は、Googleフォームの動的なデフォルト値を擬似的に設定する方法を紹介しました。まだまだ使い勝手としては不足している部分もありますが、いくらかは実用的かなと思います。私は家計簿をGoogleフォームでつけていますが、日付をデフォルトで今日にすることで、無駄な入力を省略することに利用しています。
しかしまぁ、正直なところ今後のアップデートで動的なフォームの更新に対応してほしいと思うばかりです。