- 分岐処理その2(switch構文)
- 「===」の意味は?「==」との違いは?
- 論理式
- データ型
- typeof
前回は、選択肢を持つタイプについてはその内容を取得して書き込むところまで進みました。
現状のコードでは、アイテムタイプがラジオボタンか否かだけで判別していましたが、選択肢を持つアイテムタイプは他にもありますので、「もしもラジオボタンなら」の部分を「もしもラジオボタンかチェックボックスかプルダウンか…」という形にして、同じように選択肢を持つアイテムにも対応させたいところです。
ただ、ここで問題になるのが、共通操作の前にそれぞれのタイプにキャストする「as*****Item();」という処理が必要になるということです。ここはそれぞれのアイテムタイプごとに*****の部分が異なったメソッドを書く必要があります。
for文の中の流れを上記のように少し変えます。
if (itemType == 'MULTIPLE_CHOICE') { testPartsItem = itemparts.asMultipleChoiceItem();
の部分だけを引っ張ってきて、すべてのタイプをそれぞれに応じたアイテムタイプにキャスト(変身)させてしまいましょう。
「もしアイテムタイプが●●ならば〇〇、▲▲ならば△△・・・」というような分岐は、ifでも可能ですが、もう一つの条件分岐「swich」という構文も使用できます。
//swichによりそれぞれのアイテムにキャスト switch (itemType) { case 'CHECKBOX': testPartsItem = itemparts.asCheckboxGridItem(); break; case 'CHECKBOX_GRID': testPartsItem = itemparts.asCheckboxItem(); break;
このような感じになります。
現在取得できるアイテムタイプは17種類ですが、ファイルアップロードタイプのアイテムにはキャストできません。(固有の動きがないから?)
キャストした後に、それぞれをいくつかのグループに分けて目印をつけておくとよさそうです。
選択肢がないアイテムに対してgetChoices()…なんてやってしまうと、エラーが出てそこでプログラムが止まってしまうからです。。。
つまり、共通メソッドごとにグループ分けをしていきます。
よく使用するのは、テキストボックス、ラジオボタン、チェックボックス、プルダウンあたりかと思いますので、
- 配点が確認できるタイプ(getPoint()が使えるタイプ)
- 選択肢があるタイプ(getChoices()が使えるタイプ)
現状、これらが判別できればよさそうです。
getChoices()できるのは、執筆現在で
- ラジオボタン
- チェックボックス
- プルダウン
の3種類なので、それらのcaseではキャストのあとに
- テキストボックス系
- 時間選択系
になります。
これらには、
case 'MULTIPLE_CHOICE': testPartsItem = itemparts.asMultipleChoiceItem(); hasChoice = 1; hasPoint = 1; break;
こうしておくと、もしhasChoice = 1ならば選択肢取得の処理、もしhasPoint = 1ならば、配点取得の処理…という形で共通処理をまとめることができます。
さて、これで実行・・・!
なのですが、何か様子がおかしい・・・。
選択肢が全く取得されないのです。ラジオボタンだろうがチェックボックスだろうが、シートに書き込まれるのは質問内容とアイテムタイプのみ。
慌ててコードがどこまで動いているか、Logを追加してチェック。
まずは、hasChoice が1になっているかどうか、ログを追加してみると、結果はすべて「0」のまま。。。
つまり、このswich自体がうまく機能していない(どのcaseにも入っていない)ようなのです。
こんなとき、頼りになる(ようでならない)のがChatGPT。
ChatGPTに惑わされつつ、一緒にいろいろと原因を調べた結果、swichの条件は、ifでいうと
itemType === ‘MULTIPLE_CHOICE’ (イコールが3つついています;;;)
になるそう。ちなみに前回、ifで書いた条件式は
if (itemType == 'MULTIPLE_CHOICE') {
なので、イコール2つです。イコールが3つになると、「データ型まで完全に一致した場合」ということになるらしいのです。ログを見てもどちらもMULTIPLE_CHOICEで同じに見えるんですけど、、、
試しにitemTypeのデータ型を調べるために
Logger.log(typeof itemType); //ログを確認
としてみると結果は「object」
case ‘MULTIPLE_CHOICE’:という書き方だと、string型というテキストの型になるので、
どちらもMULTIPLE_CHOICEだけど、object ≠ stringなので、厳密には一致しないということらしいです。
なにそれ、細かい…😵
じゃあ、’MULTIPLE_CHOICE’をオブジェクト型で書き直します。
オブジェクト型の書き方は、itemType.MULTIPLE_CHOICEとなります。
switchの分岐を
case itemType.MULTIPLE_CHOICE: testPartsItem = itemparts.asMultipleChoiceItem(); hasChoice = 1; hasPoint = 1; break;
と書き換えると、ちゃんと動きました😂
素人が基礎をぶっ飛ばしてコードを書くと、しばしばこのような初歩的な間違いで足止めを食らいます。
Google Apps Scriptで初めてプログラムを書いてみようと思われるかたは、せめてJavaScriptの基本的な説明が書かれている書籍を手元に置くことをお勧めします。
書籍はたいてい分厚いですが、読むのが大変であれば躓いたときにだけでもページをめくってみてください。
ここまでのコード
function myFunction() { // フォームを開く const form = FormApp.openByUrl(フォームのURL); // URLは'https://docs.google.com/fo******/edit'のように''で囲んで入力 //フォームの要素を配列で取得 const items = form.getItems(); //スプレッドシートを開く。 const spsheet = SpreadsheetApp.openByUrl(シートのURL); // URLは'https://docs.google.com/fo******/edit'のように''で囲んで入力 const sheet = spsheet.getActiveSheet(); //処理を加えるシートとして、ファイルを開いて最初に表示される(アクティブな)シートを設定 sheet.clear(); //シートの内容をクリア //シートに行を追加し、formタイトル入力 sheet.appendRow(['フォームタイトル', form.getTitle()]); // 項目タイトル行を作成 sheet.appendRow(['アイテムタイプ', '質問内容']); for (let i = 0; i < items.length; i++) { //Item数をiと置き換えて、iを0から順番に項目の数だけ1ずつ増やす const itemparts = items[i]; //itemという配列のi番目の要素をitempartsとして取り出す。 const itemType = itemparts.getType(); //取得したitempartsのタイプを確認してitemTypeに保管 const itemText = itemparts.getTitle();//取得したitempartsの質問内容を確認してitemTextに保管 // sheet.appendRow([itemType, itemText]); // それぞれシートの新しい行に入力 let itemSheetinput = [itemType, itemText]; // ↑入力ではなく一旦配列に格納 let hasChoice = 0; let hasPoint = 0; Logger.log(typeof itemType); //ログを確認 //swichによりそれぞれのアイテムにキャスト switch (itemType) { case itemType.CHECKBOX: testPartsItem = itemparts.asCheckboxItem(); hasChoice = 1; hasPoint = 1; break; case itemType.CHECKBOX_GRID: testPartsItem = itemparts.asCheckboxGridItem(); break; case itemType.DATE: testPartsItem = itemparts.asDateItem(); hasPoint = 1; break; case itemType.DATETIME: testPartsItem = itemparts.asDateTimeItem(); hasPoint = 1; break; case itemType.DURATION: testPartsItem = itemparts.asDurationItem(); hasPoint = 1; break; case itemType.GRID: testPartsItem = itemparts.asGridItem(); break; case itemType.IMAGE: testPartsItem = itemparts.asImageItem(); break; case itemType.LIST: testPartsItem = itemparts.asListItem(); hasChoice = 1; hasPoint = 1; break; case itemType.MULTIPLE_CHOICE: testPartsItem = itemparts.asMultipleChoiceItem(); hasChoice = 1; hasPoint = 1; break; case itemType.PAGE_BREAK: testPartsItem = itemparts.asPageBreakItem(); break; case itemType.PARAGRAPH_TEXT: testPartsItem = itemparts.asParagraphTextItem(); hasPoint = 1; break; case itemType.SCALE: testPartsItem = itemparts.asScaleItem(); hasPoint = 1; break; case itemType.SECTION_HEADER: testPartsItem = itemparts.asSectionHeaderItem(); break; case itemType.TEXT: testPartsItem = itemparts.asTextItem(); hasPoint = 1; break; case itemType.TIME: testPartsItem = itemparts.asTimeItem(); hasPoint = 1; break; case itemType.VIDEO: testPartsItem = itemparts.asVideoItem(); break; } Logger.log(hasChoice); //ログを確認 //選択肢取得処理開始 if (hasChoice == 1) { const choices = testPartsItem.getChoices(); //選択肢を取得 const choicesText = choices.map(x => x.getValue()); //選択肢のテキストを取得 itemSheetinput = itemSheetinput.concat(choicesText); //アイテムタイプや質問内容の配列と合体 Logger.log(itemSheetinput); //ログを確認 } sheet.appendRow(itemSheetinput); //まとめてシートの新しい行に入力 } }
コメント