GASでフォルダを複製する~Googleフォーム~
はじめに
SEVENRICH GROUP、DELTA所属の伊藤です。
相変わらず周りの方に助けられながらGAS触ってる初心者です。
自己紹介記事『超初心者がGASで死活監視するよ。』
3ヶ月前に『GASでフォルダを複製する』の記事を出しましたが、今回はその続き、Googleフォーム編です。
課題
全体の課題
同じ形式のフォームやスプレッドシートを多数用意しなければならず、1つのフォルダにまとめてフォルダごとコピー出来れば簡単なんですが、残念ながらGoogleドライブはフォルダコピーできない仕様なので、GASでまとめてファイルを複製できるようにしたいという課題でした。
前回ではフォルダの複製とファイルのタイトル変更等が出来るようになりました。
今回は複製するフォルダの中に含まれているGoogleフォームの処理です。スプレッドシートとの紐づけや、質問選択肢の変更をフォルダ作成時に自動でやってしまいたいと思います。
①「フォームの選択肢の書き換え」
回答先に合わせて質問の選択肢を変更します。
質問のこの部分を変更します↓
※実際にはこんなアンケートはありません
選択肢の内容の一覧が必要になるため、前回まで使用していたスプレッドシートの仕様を変更することに。
これまでは企業名と作成日時があるシンプルなスプレッドシートでしたが、別スプレッドシートに選択肢を一覧にして、それを取り入れる形式に。
ついでに変更の有無もここで設定するようにします。
企業名は選択肢一覧スプレッドシートに一緒に記入してIMPORTRANGEで取得しています
選択肢一覧スプレッドシートはこんな感じで用意する。
※実際にはこんなアンケートはありません
コード
const q_listurl = data_sh.getRange(i, 2).getValue(); //選択肢一覧のurlを取得
const q_list = SpreadsheetApp.openByUrl(q_listurl);//スプレッドシートを取得
var items_formA = formA.getItems() //全質問項目を取得
var q1_lastRow = q_list.getRange('B6').getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
var q1_flag = data_sh.getRange(i, 4).getValue();
var q2_lastRow = q_list.getRange('C6').getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
var q2_flag = data_sh.getRange(i, 5).getValue();
if (q1_flag == 'あり') {//ラジオボタン
var itemA_1 = items_formA[0] //質問項目の指定
var q1_List = q_list.getRange('B6:B' + q1_lastRow).getValues(); //スプシから変更内容を取得
itemA_1.asMultipleChoiceItem().setChoiceValues(q1_List).showOtherOption(false); //選択肢をフォームに反映
}
if (q2_flag == 'あり') {//チェックボックス
var itemA_2 = items_formA[1] //質問項目を指定
var q2_List = q_list.getRange('C6:C' + q2_lastRow).getValues();
itemA_2.asCheckboxItem().setChoiceValues(q2_List).showOtherOption(true);
}
参考にさせて頂いたページ:
~説明~- フォームの質問項目をすべて取得
↓ - Q1とQ2の選択肢一覧をスプレッドシートから取得
(スプレッドシートから変更内容を取得する際、変更する選択肢の数が決まっているわけではないため、少し回りくどい書き方になっていますが、「列を指定して、その列の最後の行までをリストとして取得する」という書き方です)
↓ - 選択肢の変更がありになっていたら該当の質問項目の選択肢を変更する
- Q1ではその他の項目をつけないためshowOtherOption(false)
- Q2ではその他の項目をつけるためshowOtherOption(true)
~つまずきポイント~
回答形式と変更するときのメソッドが一致していないとエラーになるため厄介でした。
絶対合ってるのに何でエラーが出るんだよと思っていたら質問項目の指定が間違っていたなんてこともしばしば。
回答形式 | メソッド |
---|---|
ラジオボタン | asMultipleChoiceItem() |
チェックボックス | asCheckboxItem() |
プルダウン | asListItem() |
②「フォームをスプレッドシートに紐づける」
コード
const ssB_Id = id_sh.getRange(i, 7).getValue(); //紐づけたいスプシのID
const ssB = SpreadsheetApp.openById(ssB_Id);//紐づけたいスプシ
const formA_Id = id_sh.getRange(i, 4).getValue();//紐づけたいフォームのID
const formA = FormApp.openById(formA_Id);
formA.setDestination(FormApp.DestinationType.SPREADSHEET, ssB.getId()); //フォームをスプレッドシートに紐づけ
新規に作成したスプレッドシートやフォームIDは前回スプレッドシートの方に記入してあるため、そこから取得しています。
setDestination(type, id) メソッドでフォームの回答先を紐づけ出来ます。
~ちなみに~
テンプレートに入ってるフォームが既にスプレッドシートに紐づいた状態でフォルダを複製するとこうなります↓
テンプレートフォルダ内のフォームと紐づいているスプレッドシートの
階層にフォームのコピーが作成されてしまう
そのためテンプレートフォルダ内のフォームとスプレッドシートは紐づけない状態にしておく。
③「回答シートの名前変更」
フォームを紐づけたスプレッドシートを見に行くと、『フォームの回答1』というシートが追加されています。このシート名を変更します。
コード
SpreadsheetApp.flush();
const ssB_sheets = ssB_Id.getSheets(); //スプシのシートを取得
for (var j = 0; j < ssB_sheets.length; j++) {
// シート名に「フォームの回答」が含まれている場合
const sh_name = ssB_sheets[j].getName(); //シート名を取得
if (sh_name == 'フォームの回答 1') {
ssB_sheets[j].setName("ローデータ_アンケート1");
};
};
~説明~
- スプレッドシート内のシートをすべて取得
↓ - for文でシート名を取得していく
↓ - シート名が『フォームの回答 1』だった場合にシート名を変更する
~つまずきポイント~
はじめ何度実行してもシートの中に『フォームの回答 1』はないというエラーが返ってきていました。でも実際にスプレッドシートを見に行くとシートはちゃんと存在していて、作成後のスプレッドシートのシートを取得してみても存在するため、どうやら直前のフォームとスプレッドシートの紐づきにラグがあるため捕捉できていないらしいということに気づきました。
調べてみると、flushというそこまでスプレッドシートの処理を反映させるメソッドがあるらしいと知ったので、祈りの気持ちでSpreadsheetApp.flush(); を追加したらちゃんとシートを捕捉できたため感動しました。
シート名を変更できれば複数のシートがあっても見つけやすいため、QUERY関数のシート指定なんかもしやすいです。
最後に
結構さらっと書きましたが、実際は複数のフォームに複数のスプレッドシートがあるため、理屈は分かっていてもエラーばかりが出るので心が折れそうでした。。(フォームの選択肢の変更らへん)そしてflashメソッドは光でした。(ここでも頭を抱えていたところを救ってくれたので)
でもフォームとか何気なく使ってるものでもこれを機に仲良くなれた気がします。
前回の『GASでフォルダを複製する』も合わせて、フォルダのコピーだけじゃなく、プラスアルファで自動化したいと思ってる方はぜひ参考にしていただけたらなと思います。
We're Hiring!
現在DELTA では一緒に働いてくださる仲間を募集中です。
ご興味お持ちいただけましたら、ぜひフォームからご連絡ください!!
Discussion