GASの応用

Googleフォームの回答内容をGoogleカレンダーに反映する方法

フォームの回答カレンダーへ GASの応用

みなさんこんにちは!GASおじさんです。

連載「GoogleフォームとGASで超実用的な予約システムを自作する」の第5回です。

前回で無事予約受付フォームが完成しました。こちらは店舗を訪れるお客様のための画面、いわば「表側」の画面です。

今回からはフォームで受け付けた内容を、Googleカレンダーに反映したり、Gmailで予約者にサンクスメールを自動返信したり、「裏側」の機能の部分を実装していきます。

今回は、「Googleフォームで受け付けた予約内容をGoogleカレンダーに反映する方法」について解説していきます。それではやっていきましょう!

回答を記録するスプレッドシートを作成

まずは回答を記録するスプレッドシートを作成します。

ちなみに、今回の機能もGASを使って実装していくのですが、利用するスクリプトエディタは、回答を記録するスプレッドシートに紐づいたスクリプトエディタを利用します

前回と前々回では、Googleフォーム編集画面からスクリプトエディタを開きました。つまり今まで使っていたスクリプトエディタはGoogleフォームに紐づいているのですが、今回はこちらは利用しませんのでご注意ください。

その理由については後ほど説明します。

それではスプレッドシートを作成します。

  1. 「回答」タブを開く
  2. 「スプレッドシート作成」のアイコンをクリック

モーダルウィンドウが開くので、「新しいスプレッドシートを作成」を選択肢、「作成」をクリックしてください。

するとGoogleフォームで受け付けた回答が記録されたスプレッドシートが生成されました。

今回はこちらのスプレッドシートのコンテナバインドスクリプトを使って実装していきます。

メニューバーの「拡張機能」から「Apps Script」をクリックしてください。

エディタを開いたらプロジェクト名を「見学予約フォーム」としておきましょう。

フォームの回答をGoogleカレンダーに反映するスクリプト

それではGASを実装します。まずは以下のコードをコピーしてエディタに貼り付けてください。

function createEvent(e) {
  let [timestamp, email, username, date, time] = e.values;
  let id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; //GoogleカレンダーのID
  let calendar = CalendarApp.getCalendarById(id);
  let title = `【見学】${username}様`;

  let y = Number(date.split('年')[0]);
  let m = Number(date.split('年')[1].split('月')[0]) - 1;
  let d = Number(date.split('月')[1].split('日')[0]);
  let hours = Number(time.split(':')[0]);
  let minutes = Number(time.split(':')[1]);
  let startTime = new Date(y, m, d, hours, minutes);
  let endTime = new Date(y, m, d, hours, minutes+60);

  let description = 

`▼申込内容
予約日時: ${timestamp}
Eメール: ${email}
お名前 : ${username}
見学日 : ${date}
見学時間: ${time}`;

  let options = {
    description: description,
  };
  calendar.createEvent(title, startTime, endTime, options);
}

以下のようなかんじ。

スプレッドシートに紐づいたスクリプトエディタを使う理由

ここで2行目のコード、

let [timestamp, email, username, date, time] = e.values;

にご注目ください。

こちらはフォームから受け取るそれぞれの回答に変数名をつけている部分になります。

先ほどスクリプトエディタを開く際に、Googleフォームの画面から開くのではなく、スプレッドシートの画面から開くように注意を促しましたが、その理由はここにあります。

このコードの右辺e.valuesが、スプレッドシートに紐づいたスクリプトじゃないと有効にならないんですね。

これはGoogleフォームで受け取れるイベントオブジェクトと、スプレッドシートで受け取れるイベントオブジェクトに違いがあるからです。

イベントオブジェクトについて詳しい解説はここでは割愛しますが、詳しく知りたい方は以下の公式リファレンスをご参照ください。

Event Objects  |  Apps Script  |  Google for Developers

とりあえずGoogleフォームに紐づいたスクリプトなのか、スプレッドシートに紐づいたスクリプトなのかで、動きが変わってくるということですね。

カレンダーIDの設定

次にコード3行目のlet id = 'xxxxxxxxxxxxxxxx';にIDを反映させましょう。Googleカレンダーを開いてIDを調べます。

GASおじさんは「見学予約」というカレンダーを作成して、ここに記録していくことにします。

「見学予約」の右にある「︙」をクリックします。

「設定と共有」をクリックします。

左サイドメニューの「カレンダーの統合」をクリックすると、カレンダーIDの箇所までスクロールできます。

こちらの「カレンダーID」をコピーして、エディタの3行目に貼り付けます。

貼り付けたらCtrl + SまたはCommand + Sでファイルを保存しておきましょう。

これでスクリプトは完成です!次にトリガー設定を行います。

なお、コードの詳しい解説は別途Youtubeで解説予定です。

フォーム送信時トリガーを設定

次に作成したスクリプトにトリガーをかけたいと思います。

左のメニューの中から「トリガー」をクリックします。

画面右下の「トリガーを追加」をクリックします。

以下の手順でトリガー設定します。

  1. 実行する関数で「createEvent」を選択
  2. イベントの種類は「フォーム送信時」を選択
  3. エラー通知設定は「今すぐ通知を受け取る」を選択
  4. 保存

アクセス権限の承認を求められた場合は、承認しましょう。承認方法がわからない場合は、以下の記事を参照してください。

これで設定完了です!

プレビューで確認

それでは動作するか確認してみましょう。Googleフォームのプレビュー画面を開いてみてください。

ちなみに、スプレッドシートのメニューバー「ツール」>「フォームを管理」>「実際のフォームを開く」からフォームを開くことができます。

各項目を入力して送信してみます。

送信後Googleカレンダーを確認してみると…

フォームの回答内容がしっかり反映されていることが確認できました!

まとめ

以上、「Googleフォームで受け付けた予約内容をGoogleカレンダーに反映する方法」を解説してきました。

結構簡単に実装できたのではないかなと思います。

ただこの記事の通りに実装すると1時間分の予定しか作成できないので、たとえば、

「2時間分の予定を作成したいときはどうしたらいいの?」

などの課題に対応するためには、コードの書き換えを行わなければなりません。

そのためにはコードの理解が必要です。コードの詳しい解説については、以下のYoutubeで解説していますので、必要な方はぜひご覧ください。

次回は「Googleフォーム回答後サンクスメールを自動返信する方法」について解説していきます。そのまま次に進まれる方は以下からどうぞ!

よくある質問(2023/04/21更新)

当記事について、よくある質問をまとめていきます。

TypeError: Cannot read properties of undefined (reading ‘values’)

「スクリプトを実行すると、以下のようなエラーが出ます。どうしたらいいですか?」という質問です。

TypeError: Cannot read properties of undefined (reading ‘values’)
createEvent @ コード.gs:2

これはコード2行目のe.valuesが読み込めませんよ、という意味のエラーです。

e.valuesというのは、当記事でも解説している通り、Googleフォームから受け取る回答のことを指しています。

このエラーが出てくると言うことは、おそらく、エディタ上でcreateEvent関数を実行しているのではないでしょうか?

エディタ上で実行すると、Googleフォームからの回答を受け取りようがないので、このエラーが発生することになります。

エディタから実行するのではなく、フォーム送信時トリガーを設定後、Googleフォームを送信することによってトリガー実行させてください。

トリガー実行が成功したかどうかは、左サイドメニューの「実行数」の画面で確認可能です。

トリガー実行をしてもうまくいかないときは、エラーログを確認しましょう。

このエラーログが直接のヒントです。まずはこのエラーログをググってみたりして紐解いてください。それでもわからなければ、書いたコードとエラー文をセットにしてご相談ください。

連載目次: GoogleフォームとGASで超実用的な予約システムを自作する

  1. GoogleフォームとGASで超実用的な予約システムを自作する
  2. Googleフォームで予約受付フォームを作ろう
  3. Googleフォームの日付選択をプルダウンにして入力内容を制限する方法
  4. Googleフォームの時間入力をプルダウンにしてキリのいい時間を入力させる方法
  5. Googleフォームの回答内容をGoogleカレンダーに反映する方法
  6. Googleフォーム回答後サンクスメールを自動返信する方法
  7. Googleフォームで営業時間外の予約を受付拒否する方法

GASを勉強するならこちら!

▼オススメ書籍はこちら!

スポンサーリンク
GASおじさんをフォローする
GASおじさんのブログ

コメント

  1. shigeru より:

    自社サイトからの予約をGoogleカレンダーに自動反映させる方法を調べていたらこのサイトに辿り着きました。
    非常に詳しく説明されていてありがたいです!

    しかし「フォーム送信時トリガーを設定」する際に、どうしても実行権限が承認されません。
    間違いなく自分自身のGoogleアカウントを選択しているのですが、「Google hasn’t verified this app」となり、先に進めません。。。

    何が間違っていると思いますか?
    アドバイスをお願いいたします!

    • GASおじさん GASおじさん より:

      コメントありがとうございます。

      おそらく承認権限の付与のことですね。
      「Google hasn’t verified this app」の画面が出てきたら、左下の「Advanced」をクリックしてください。
      するとさらに左下に「Go to xxxxxx(unsafe)」という記述がありますので、そちらをクリックし、最後に「Allow」をクリックしてください。
      それで実行できるようになるはずです。

      詳しくは「gas 承認権限」などでヒットする記事等を参考にしてみてください。

  2. shigeru より:

    できました!
    ありがとうございます!

    その後、すべてが終わったので送信してみたのですが、メールも届かず、カレンダーにもまったく反映されないので、「フォームの回答をGoogleカレンダーに反映するスクリプト」を実行してみたところ、次のようなエラーが出ました。
    これは何を意味しているのでしょうか?

    エラー
    TypeError: Cannot read properties of undefined (reading ‘values’)
    createEvent @ コード.gs:2

    • GASおじさん GASおじさん より:

      それはコード2行目のe.valuesが読み込めませんよ、という意味のエラーです。
      e.valuesというのは、本記事でも解説している通り、Googleフォームから受け取る回答のことを指しています。

      状況から推測するに、おそらく、エディタ上でcreateEvent関数を実行しているのではないでしょうか?
      エディタ上で実行すると、Googleフォームからの回答を受け取りようがないので、そのエラーが出てしまうことになります。

      フォーム送信時のトリガーは設定できていますでしょうか?
      Googleフォームの送信と同時に、createEvent関数が実行されるようにする必要があります。

      • shigeru より:

        ありがとうございます。

        なるほど。。。そういう仕組みだったんですね。。。
        おっしゃる通り、エディタ上でcreateEvent関数を実行した結果でした。^^;

        > フォーム送信時のトリガーは設定できていますでしょうか?

        一応、指示通りに順番にやっていったのでトリガーも間違いなく設定されていると思うのですが、もう一度チェックしてみます。

        • GASおじさん GASおじさん より:

          ちなみにトリガー実行の結果については、左メニューの「実行数」から確認できます。
          その画面で、種類が「トリガー」、ステータスが「失敗しました」となっているものを確認してみてください。
          そちらに記載されているエラー内容がより詳しいエラー内容となっているはずなので、解決のヒントになると思います。

          • shigeru より:

            できました!
            結局、原因はGoogleカレンダーのカレンダーIDを間違えていただけでした。。。^^;
            勝手に「@group.calendar.google.com」より前の部分だけがIDだと勘違いして、それを貼っていました。。。お騒がせしました!

            これからこれを元に自社の予約をGoogleカレンダーに自動的に読み込めるような仕組みを作ってみたいと思います。
            できるのだろうか。。。(笑)

          • GASおじさん GASおじさん より:

            よかったです✨健闘を祈ります!

  3. shigeru より:

    すみません。。。図々しいお願いなのですが、スプリクトを見ていただけないでしょうか?

    早速、自社の予約時の取得項目(30点あります)をGoogleカレンダーに反映させるべく、そのまま教えていただいたスクリプトに当てはめてみました。
    しかし、何度やってもカレンダーには反映されず、エラーメールだけが届いています。(トリガーも設定しています)

    以下のスクリプトなのですが、何かおかしな点はありますでしょうか?
    上手くいかない理由として考えられることを教えていただけませんでしょうか?
    よろしくお願い致します。

    function createEvent(e) {
    let [timestamp, lastname, firstname, tel, email, route, url, date, unprocessed, charter, time, number, pay, price, stay, rentacar, pickup, inday, intime, outday, outtime, name1, age1, sex1, height1, weight1, feet1, lens1, eye1, remarks] = e.values;
    let id = ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@group.calendar.google.com’; //GoogleカレンダーのID
    let calendar = CalendarApp.getCalendarById(id);
    let title = `${unprocessed}${charter}【${time}】${lastname}${number}名(${stay})`;

    let y = Number(date.split(‘年’)[0]);
    let m = Number(date.split(‘年’)[1].split(‘月’)[0]) – 1;
    let d = Number(date.split(‘月’)[1].split(‘日’)[0]);
    let hours = Number(time.split(‘:’)[0]);
    let minutes = Number(time.split(‘:’)[1]);
    let startTime = new Date(y, m, d, hours, minutes);
    let endTime = new Date(y, m, d, hours, minutes+150);

    let description =

    `${route}
    ${url}

    ★ 参加希望ツアー
    ${date} ${time} 体験ダイビングツアー ${number}名${charter}
    ${charter}【${time}】${lastname}${number}名(${stay})

    ★ 代表者
    氏名:${lastname} ${firstname}
    携帯電話番号:${tel}

    ★ お支払い
    お支払い方法:${pay}
    お支払い金額:
    ${price}

    ★ 宿泊と送迎
    宿泊先:${stay}
    送迎:${pickup} / ${rentacar}

    ★ 日程
    到着日:${inday} 交通手段: ${intime}
    お帰りの日:${outday} 交通手段: ${outtime}

    ★ 参加者データ
    ${name1} ${age1} ${sex1} ${height1} / ${weight1} / ${feet1}
    ${name1} ${lens1} ${eye1}

    ★ 参加人数:${number}名

    ★ メッセージ本文:
    ${remarks}

    ★ 予約日:${timestamp}`;

    let options = {
    description: description,
    };
    calendar.createEvent(title, startTime, endTime, options);
    }

    • GASおじさん GASおじさん より:

      コメントありがとうございます。
      スクリプトだけだと分析が難しいので、エラー文をご教示いただけますでしょうか?
      エラーメールのError Messageです。

      • shigeru より:

        お世話になります。

        エラーメッセージは”Summary of failures for Google Apps Script: 体験ダイビングツアー”というタイトルのメールで送られてきているのですが、内容は以下のようなものです。

        Your script, 体験ダイビングツアー, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.

        The script is used by the document 【フォームの名前】.

        Start:
        2023-02-25 14:18:41 Japan Standard Time

        Function:
        createEvent

        Error Message:
        TypeError: Cannot read properties of undefined (reading ‘split’)

        Trigger:
        formSubmit

        End:
        2023-02-25 14:18:42 Japan Standard Time

        • GASおじさん GASおじさん より:

          ありがとうございます。ここで重要なのは、

          TypeError: Cannot read properties of undefined (reading ‘split’)

          というエラー文です。
          これは「splitメソッドが動いていないですよ」という意味です。
          したがって原因は、以下の記述の部分にありそうです。

          ————-
          let y = Number(date.split(‘年’)[0]);
          let m = Number(date.split(‘年’)[1].split(‘月’)[0]) – 1;
          let d = Number(date.split(‘月’)[1].split(‘日’)[0]);
          let hours = Number(time.split(‘:’)[0]);
          let minutes = Number(time.split(‘:’)[1]);
          ————-

          splitメソッドは「文字列を分けて配列にする」ということをしてくれます。

          ————-
          date = ‘2023年2月25日’;
          let y = Number(date.split(‘年’)[0]);
          ————-

          上記の2行は、「2023年2月25日」という文字(date)を、「年」という文字を境にして配列に分けて、その0番目の要素、つまり2023という数字を、変数yとして定義する、ということをしています。

          したがって、もし変数dateの内容が、「2023年2月25日」という文字ではなく、「2023/02/25」みたいな文字だった場合、「年」という文字がみつからないために、splitできない、というようなエラーが発生します。

          これをヒントにして、dateやtimeの内容について確認してみてください。

  4. shigeru より:

    まったく、その通りでした。。。^^;
    今日はずっと、GASおじさんの「コード解説」動画などを見ながら日付や時間関連のスクリプトを勉強させていただきました。

    今回、作っているフォームはお客様ではなく、うちのスタッフだけが使うもので、様々な媒体から入ってくる予約を常に同じフォーマットでGoogleカレンダーに入力するためのツールとして作っています。

    なので日付と時間の入力はいつも必ず同じフォーマットで入力できるので、最初の

    3.Googleフォームの日付選択をプルダウンにして入力内容を制限する方法
    4.Googleフォームの時間入力をプルダウンにしてキリのいい時間を入力させる方法

    はスルーしていたのが原因でした。
    結局、もともと終日イベントにしたかったこともあり、

    let hours = Number(time.split(‘:’)[0]);
    let minutes = Number(time.split(‘:’)[1]);
    let startTime = new Date(y, m, d, hours, minutes);
    let endTime = new Date(y, m, d, hours, minutes+60);

    の部分はすべて取り去り、代わりに

    let day = new Date(y, m, d);

    を入れました。また、

    calendar.createEvent(title, startTime, endTime, options);

    calendar.createAllDayEvent(title, day, options);

    に変えました。
    一応、普通に動いていますがこれで良かったのでしょうか?

    ただ、Googleフォームの日付選択プルダウンは365日分にしているせいか(予約は1年前から入るため)、メチャクチャ重くカレンダー入力に戻したいのですが、どうしてもカレンダー入力からyyyy年M月d日(${days[day]})の形式に変換する方法が分からず、現在も重いフォームから予約を入力しています。(笑)

    それと。。。
    当店では最大で一枠に8人グループまでは受け入れるため、予約時に最大8人分のデータ(身長や体重、年齢や性別など)を取得する必要があります。
    しかし、通常は1件の予約は2-3名のグループである事が多いので、残り5-6名分の入力フォームは丸々無駄になって送信することになります。

    Googleカレンダーへの出力も5-6名分のブランク(スペース=空白)が空き、なんかイケてないです。。。(笑)

    Googleフォームでは、お客さんが3名の時は3名分の入力フォームが、8名の時は8名分の入力フォームが表示されるという感じで、人数に合わせてアンケート項目を増減させたりすることができたりしますか?

    長くなりました。。。申し訳ないです。。。

    • GASおじさん GASおじさん より:

      コメントありがとうございます。

      一応、普通に動いていますがこれで良かったのでしょうか?

      動いているならそれでいいと思います!

      ただ、Googleフォームの日付選択プルダウンは365日分にしているせいか(予約は1年前から入るため)、メチャクチャ重くカレンダー入力に戻したいのですが、どうしてもカレンダー入力からyyyy年M月d日(${days[day]})の形式に変換する方法が分からず、現在も重いフォームから予約を入力しています。

      うーん、for文を365回ループさせたくらいでそんなに重くなることはないと思うのですが…原因は別のところにありそうな気がします。
      まあたしかに、そもそも365日分も選択肢を用意するんだったら、通常のカレンダー入力に戻した方がよさそうですね。
      文字の変換方法については、一度javascriptの基礎文法を学習してみることをおすすめいたします。

      人数に合わせてアンケート項目を増減させたりすることができたりしますか?

      セクション機能を使えばできそうかな〜と思いました。

      「参加人数」という項目を用意して、
      「2人」の場合は、2人分のデータを入力するセクションに誘導し、
      「3人」の場合は、3人分のデータを入力するセクションに誘導する、
      みたいなかんじですね。

      「Googleフォーム セクション 分岐」などで調べてみてください!

  5. 伊東 明洋 より:

    会社のスタッフの予定管理をGoogleフォームで入力してカレンダーに飛ばす方法が無いかと思って調べていたら、こちらのサイトにたどり着きました。
    Youtubeも拝見させていただきながら、GASを作成しているのですが、なかなかうまくいきません。。。

    左メニューの実行数のところのエラーが
    Script function not found: createEvent
    となっているのですが、何でそうなるのかわかりません。
    もしよろしければ、お教えいただけませんでしょうか?

    やりたいこと
    ・外出内容(6項目程度)、外出予定日(こちらで学ばせていただき、当日から3日間だけ選べるようにしました。)、出発時間、戻り予定時間を選んで、フォーム送信すると、選んだ日時のGoogleカレンダーに予定が入るようにしたい。

    ※下記、現状、スプレッドシート側のGASです。

    function createcalendar(e) {
    let[timestamp,contents,date,start,end] = e.values;

    let title = `${contents}`;

    let y = Number(date.split(‘年’)[0]);
    let m = Number(date.split(‘年’)[1].split(‘月’)[0])-1;
    let d = Number(date.split(‘月’)[1].split(‘日’)[0]);

    let startHours = Number(start.split(‘:’)[0]);
    let startMinutes = Number(start.split(‘:’)[1]);

    let endHours = Number(end.split(‘:’)[0]);
    let endMinutes = Number(end.split(‘:’)[0]);

    let startTime = new date(y,m,d,startHours,startMinutes);
    let endTime = new date(y,m,d,endHours,endMinutes);

    let id = ‘カレンダーID’;
    let calendar = CalendarApp.getCalendarById(id);
    calendar.createEvent(title,startTime,endTime);

    }

    この状態でフォーム送信をすると、先ほどのエラーが出てしまいます。。

    • 伊東 明洋 より:

      大変申し訳ありません!

      できました!

      new dateのdateがDateにしなければならなかったのですね!

      ありがとうございます!

      • GASおじさん GASおじさん より:

        ナイス自己解決です!
        プログラムは1文字でも間違えると動かなくなるので、慣れるまでは大変ですよね。
        コピペや予測変換を使ってなるべくタイプミスを避けていきたいところです。
        上達してくるとそういった些細なミスも少なくなっていきますし、仮にミスをしても一瞬で気づけるようになってくるので、ひたすら鍛錬あるのみですね!

        • 伊東 明洋 より:

          ありがとうございます!
          頑張ってやってみます!

          ブログにYoutubeと、とても分かりやすく解説されており、今後も勉強させていただきます!
          よろしくお願いします!

  6. 伊東 明洋 より:

    何度も大変申し訳ありません。
    アドバイスいただけますと幸いです。。

    会社のスタッフの予定入力を簡素化するために今回のGASを作成したのですが、
    たとえば、「佐藤」「鈴木」「高橋」などのスタッフ名をフォームで選ばせて、フォーム送信し、スプレッドシートから各々のカレンダーを選んで予定を入力できるのようにできるでしょうか?
    swichとcaseを使えばできそうな気はするのですが・・・

  7. 伊東 明洋 より:

    できました!

    e.valuesの中にusernameと入れて変数名にし、

    下の方で
    switch (username){
    case “佐藤”:
    id = ‘佐藤のカレンダーID’;
    break;
    case “鈴木”:
    id = “鈴木のカレンダーID”;
    break;
    case “高橋”:
    id = “高橋のカレンダーID”;
    break;
    }

    let calendar = CalendarApp.getCalendarById(id);
    calendar.createEvent(title,startTime,endTime,options);

    }

    としたとこと、うまく分けてカレンダー登録できました!
    ありがとうございます!

    • GASおじさん GASおじさん より:

      またも自己解決!すばらしいです!
      switchやifで条件分岐させるのも一つの手ですね。
      または、連想配列(オブジェクト)を使うのもいいかなと思います。

      let ids = {
      ‘佐藤’: ‘佐藤のカレンダーID’,
      ‘鈴木’: ‘鈴木のカレンダーID’,
      ‘高橋’: ‘高橋のカレンダーID’,
      };

      let id = ids[username];
      let calendar = CalendarApp.getCalendarById(id);

      このようにすると、コード量がより少なくなるのでオススメです!

  8. 伊東 明洋 より:

    コメントありがとうございます!

    すごい!こんな短く書けるのですね
    プログラム言語って、色々な記載方法があるので、面白いですよねw

    専門的にプログラムを習ったことが無いのですが、いろいろといじってみるとなかなか面白く、うまく動くと年甲斐もなく喜んでしまいますw

    ありがとうございます!

    • GASおじさん GASおじさん より:

      ありがとうございます!

      これは「連想配列」といったり、「オブジェクト」と言ったりします。
      ちなみにPythonでは「辞書」といったり、Rubyでは「ハッシュ」と言ったり、呼び方はさまざまあるのですが、どれも同じようなものですね。

      連想配列については、「配列」と比較すると理解しやすいと思います。

      配列は複数のデータを扱うための概念ですね。

      let names = ['sato', 'suzuki', 'tanaka'];

      みたいに、四角括弧(ブラケット)の中に複数のデータを格納することができます。
      それぞれのデータ(要素)には「インデックス番号」という0番からはじまる番号が付与されます。
      上記の場合、names[0]はsatoで、names[1]はsuzuki、そしてnames[2]はtanakaのことですね。

      連想配列も同様に、複数のデータを扱うことができるのですが、こちらは番号ではなく独自のキーを与えることができます。

      let names = {'A012': 'sato', 'B983': 'suzuki', 'C467': 'tanaka'};

      みたいに、波括弧(ブレイス)の中に複数のデータを格納することができます。
      その際、それぞれのデータには’A012’のような独自のキーを与えることができます。
      上記の場合、names['A012']はsatoで、names['B983']はsuzukiで、names['C467']はtanakaのことですね。

      * * *

      いろいろ苦難もありますが、最終的に意図した通りにプログラムが動いてくれると、最高に楽しいですよね。
      もっとプログラミングの楽しさが世に広まればいいな〜と思います☺️

      • 伊東 明洋 より:

        お世話になっております。
        以前、ご質問させていただき、上記、「連想配列」にてスタッフの外出予定を作ることができたのですが、スタッフから「2名で外出する際に、別々のカレンダーに予定を入れることができるか?」という要望がきました。
        そこで、GASおじさまがアップされているYoutubeの「異なるGoogleフォームからそれぞれのカレンダーに反映させる」の改善前のGASを逆参考にして、

        let ids = {
        ‘佐藤’: ‘佐藤のカレンダーID’,
        ‘鈴木’: ‘鈴木のカレンダーID’,
        ‘高橋’: ‘高橋のカレンダーID’,
        ‘佐藤・鈴木’: ‘佐藤のカレンダーID’,
        ‘佐藤・高橋’: ‘佐藤のカレンダーID’,
        ‘鈴木・高橋’: ‘鈴木のカレンダーID’,
        };
        let id = ids[username];
        let calendar = CalendarApp.getCalendarById(id);
        calendar.createEvent(title,starttime,endtime,option)

        ids = {
        ‘佐藤・鈴木’: ‘鈴木のカレンダーID’,
        ‘佐藤・高橋’: ‘高橋のカレンダーID’,
        ‘鈴木・高橋’: ‘高橋のカレンダーID’,
        };
        id = ids[username];
        calendar = CalendarApp.getCalendarById(id);
        calendar.createEvent(title,starttime,endtime,option)

        としたところ、Googleフォームの回答によって2名のカレンダーに予定は入るようになり、動き的には問題ないのですが、

        なぜか、1名の回答を選んだ場合、
        Cannot read properties of null (reading ‘createEvent’)
        at createcalendar
        というエラーメッセージがメールで届くようになってしまいました。

        たぶん、上記の部分には1名のところがあるのに、
        下の部分に1名のところがない事が問題なんだろうとは思うのですが、色々とやってみましたが、解決に至りませんでした。

        このエラーメッセージを回避する方法が何かしらありますでしょうか?

  9. ぺこ より:

    本ブログ通りにコーディングしてみましたが、以下のエラーが出てしまいます。
    対策を教えていただければと思います。

    TypeError: Cannot read properties of undefined (reading ‘values’)
    createEvent @ コード.gs:2

    • GASおじさん GASおじさん より:

      それはコード2行目のe.valuesが読み込めませんよ、という意味のエラーです。
      e.valuesというのは、本記事でも解説している通り、Googleフォームから受け取る回答のことを指しています。

      状況から推測するに、おそらく、エディタ上でcreateEvent関数を実行しているのではないでしょうか?
      エディタ上で実行すると、Googleフォームからの回答を受け取りようがないので、そのエラーが出てしまうことになります。

      フォーム送信時のトリガーは設定できていますでしょうか?
      Googleフォームの送信と同時に、createEvent関数が実行されるようにする必要があります。

  10. ぺこ より:

    トリガーを編集
    ・実行する関数を選択:createEvent
    ・デプロイ時に実行:Head
    ・イベントのソースを選択:スプレッドシートから
    ・イベントの種類を選択:フォーム送信時
    ・エラー通知設定:今すぐ通知を受け取る

    となっていますが、何か間違えてますでしょうか?

    • GASおじさん GASおじさん より:

      設定はそれであっています。
      その状態でGoogleフォームを送信してみてください。
      それでうまく動かないのであれば、エラー文を確認してください。
      エラー文の確認方法は以下の2通りです。

      ① 左メニューの「実行数」の画面で、ステータスが「失敗しました」となっているタブを開いて確認する
      ② 「Summary of failures for Google Apps Script: xxxxxx」という件名のメールを確認

      そちらに記載のエラー文を確認すると、より詳細な原因が解析できるはずです。

      • ぺこ より:

        早速ありがとうございます!
        このようなエラーが確認できました。

        ①Head createEvent エディタ 2023/03/28 21:21:20 0.305 秒
        失敗しました

        Cloud のログ
        2023/03/28 21:21:20 エラー TypeError: Cannot read properties of undefined (reading ‘values’) at createEvent(コード:2:52)

        ②以下のようなメールが届きました。
        Your script, プロジェクト名, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.

        The script is used by the document 名前.

        Start Function Error Message Trigger End
        2023-03-26 16:07:19 Japan Standard Time createEvent ReferenceError: username is not defined formSubmit 2023-03-26 16:07:22 Japan Standard Time
        Sincerely,

        Google Apps Script

        • GASおじさん GASおじさん より:

          そのエラー文で一番重要な部分は、

          ReferenceError: username is not defined formSubmit

          です。

          「usernameという変数が定義されていないですよ」というエラーですね。
          usernameという変数を定義する以下の部分で、タイプミスをしているなどが考えられます。

          let [timestamp, email, username, date, time] = e.values;

          一度コード全体を丁寧に見直してみてください。

          • ぺこ より:

            ありがとうございます!
            再度コピペしてみると、
            「TypeError: Cannot read properties of null (reading ‘createEvent’)」
            のエラーがメールに送られてきました。

            こちらはどのように対応すれば良いのでしょうか?

          • GASおじさん GASおじさん より:

            実装したコードを教えてもらえるとよりアドバイスがしやすいです。
            コピペしたコードをそのままここに貼り付けてもらえますか?

  11. ぺこ より:

    コメントができないようなのですが、どうすれば良いでしょうか!?

    • GASおじさん GASおじさん より:

      お問い合わせフォームまたはメールで送ってみてください。

      お問い合わせフォーム:
      https://uncle-gas.com/contact/

      メール:
      unclegas023@gmail.com

    • GASおじさん GASおじさん より:

      メールありがとうございました。以下がコードですね。

      function createEvent(e) {
      let [timestamp, email, username, datetime] = e.values;
      let id = カレンダーのID@group.calendar.google.com’; //GoogleカレンダーのID
      let calendar = CalendarApp.getCalendarById(id);
      let title = `【カウンセリング】${username}様`;

      //2022/02/21 10:00:00
      let y = Number(datetime.split(‘/’)[0]);
      let m = Number(datetime.split(‘/’)[1])- 1;
      let d = Number(datetime.split(‘/’)[2]);
      let hours = Number(datetime.split(‘ ‘)[1].split(‘:’)[0]);
      let minutes = Number(datetime.split(‘:’)[1]);
      let startTime = new Date(y, m, d, hours, minutes);
      let endTime = new Date(y, m, d, hours, minutes+30);

      let description =

      `▼申込内容
      予約日時: ${timestamp}
      Eメール: ${email}
      お名前 : ${username}
      見学日 : ${date}
      見学時間: ${time}`;

      let options = {
      description: description,
      };
      calendar.createEvent(title, startTime, endTime, options);
      }

      で、これに対するエラーが以下ということですね。

      TypeError: Cannot read properties of null (reading ‘createEvent’)

      これは、最後の1行のcalendar.createEvent(title, startTime, endTime, options);の部分がうまく動いていないというエラーです。

      calendarオブジェクトに対してcreateEventメソッドを使っているのですが、createEventが読み込めないよ、という意味です。

      ということは、calendarオブジェクトの定義部分に原因がありそうです。

      let id = カレンダーのID@group.calendar.google.com’; //GoogleカレンダーのID
      let calendar = CalendarApp.getCalendarById(id);

      let id = 'xxxxxxxxxxxxxx';でカレンダーIDを定義し、
      そのIDからcalendarオブジェクトを取得しているわけですが、このIDはきっちり正しいものになっているでしょうか?

      おそらくこのIDが間違っているがために起きているエラーだと思われます。
      以下の動画の24分8秒あたりをじっくり見てみて、どの部分をコピーしているか、丁寧に観察してみてください。

      https://youtu.be/rqlKFg4Rexw

  12. GASおじさん GASおじさん より:

    (お問合せフォームからの質問を代理入力)
    面接予約フォームを入力すると自動でカレンダーに登録されうようにしたく、
    GASおじさんのサイトにいきつきました。

    こちらのサイトを参考にさせて頂き、
    GASを作成し、フォーム送信すればカレンダーに反映はされ、
    招待者にも反映はされるのですが、
    メール通知がきません。
    let options = にて
    sendInvites: true
    としても通知がこないのですが、どうしたら良いのでしょうか。
    とくにエラーとかは発生せず、
    カレンダー反映だけされるといった感じです。
    スクリプトは下記となっています。

    function createEvent(e) {
    let [timestamp, username, date, time, medium, method] = e.values;
    let id = ‘xxxxxxxxxxxxxxxxxxxxx’;//GoogleカレンダーのID
    let calendar = CalendarApp.getCalendarById(id);
    let title = `【面接】${username}様`;

    let y = Number(date.split(‘年’)[0]);
    let m = Number(date.split(‘年’)[1].split(‘月’)[0]) – 1;
    let d = Number(date.split(‘月’)[1].split(‘日’)[0]);
    let hours = Number(time.split(‘:’)[0]);
    let minutes = Number(time.split(‘:’)[1]);
    let startTime = new Date(y, m, d, hours, minutes);
    let endTime = new Date(y, m, d, hours, minutes+30);

    let description =

    `▼面接情報
    受付日時 : ${timestamp}
    応募者名 : ${username}
    面接日  : ${date}
    面接時間 : ${time}
    応募媒体 : ${medium}
    面接方法 : ${method}`;

    let options = {
    description: description,
    guests: ‘招待者のID,招待者のID’,
    sendInvites: true,
    };
    calendar.createEvent(title, startTime, endTime, options);
    }

    • GASおじさん GASおじさん より:

      お問合せありがとうございます。
      ためしにこちらでも試してみたところ、以下のようになりました。

      • 3行目のカレンダーIDに、新しく作成したカレンダーのIDを指定した場合、招待メールが届かない
      • 3行目のカレンダーIDに、メインのカレンダーID(利用中のGmailのアドレス)を指定した場合、招待メールが届く

      以上のことから、おそらくsendInvitesオプションは、メインのメールアドレスのみ有効だと思われます。

  13. 初心者 より:

    参考にさせていただきました。
    何度やってもこちらのエラーが出てきてしまいます。TypeError: Cannot read properties of undefined (reading ‘values’)
    createEvent @ 仮.gs:2

    スプレッドシートからスクリプトエディタを利用し、トリガーを設定、実行の認識で合っておりますでしょうか?
    初歩的な質問となり申し訳ございません。

    • GASおじさん GASおじさん より:

      コメントありがとうございます。

      スプレッドシートからスクリプトエディタを利用し、トリガーを設定、実行の認識で合っておりますでしょうか?

      はい、それであっておりますが、「実行する」というのは、エディタ上で実行していたりしませんか?
      エディタで実行すると、そのエラーが発生します。

      そのエラーはコード2行目のe.valuesが読み込みできないですよ、という意味のエラーです。

      e.valuesというのは、Googleフォームからの回答のことですね。エディタから実行すると、Googleフォームからの回答を受け取れないので、そのエラーが出ることになります。

      エディタから実行するのではなく、Googleフォームを送信することによってトリガー実行させてください。
      トリガー実行が成功したかどうかは、左サイドメニューの「実行数」の画面で確認可能です。

  14. メルルーサ より:

    はじめまして。マンションの来客用の駐車場の予約表を自作したいと思って色々調べたらここにたどり着きました。プログラムやコーディングの知識が全くない私が、youtubeやブログを見ていたら自分で作れてるような気持ちになってきて、勉強したい気持ちにさせてくれてます。とてもありがく拝見してます。コメントにこんなに丁寧に返答しているのを拝見して、ついついお礼のコメントをしたくなりました。とてもためになります。凄いです!これからも楽しみにしてます。

    • GASおじさん GASおじさん より:

      嬉しいコメントありがとうございます!プログラミングの楽しさが伝わっているようで何よりです。現場で実際に役に立つモノづくりができると、楽しく学べますよね。それを意識してコンテンツを作るように心がけています。みなさんのコメントを反映すればより充実したコンテンツになっていきますので、たくさんのコメントお待ちしております!

  15. しらす より:

    はじめまして。

    前任者が作成したフォーム回答からカレンダーへの反映が全くされなくってなってしましたため、プログラミングの知識がまったくない者ながら原因を調べていたらこのサイトに行きつきました…。

    トリガーの設定は行っており、実行数は完了になっているのですが
    どうしてもグーグルフォームに反映されません。
    なにがまちがっているのでしょうか…
    可能でしたらお知恵を貸していただけますと幸いです。

    • GASおじさん GASおじさん より:

      コメントありがとうございます。

      こちら以下のライブ配信で回答を試みたのですが(2個目の質問、16:20から)、前提条件が不足していて回答できませんでした。すみません。。

      https://youtube.com/live/N1x8yUo3cKA?feature=share

      動画内でも言っているのですが、もう少し詳しく状況を教えてもらえたら、答えられることがあるかもしれません。

  16. ぜし より:

    はじめまして。
    プログラムの知識はほとんどないのですが、地域のイベントをみんなでGoogleカレンダーで共有するサイトを作成したいと思い、こちらにたどり着きました。大変わかりやすい内容のため、やりたいことが殆ど叶いました。ありがとうございます。
    少し欲張って、Googleカレンダーに「予定の場所」も一緒に登録できないだろうか?といろいろ試しているのですが、なかなかうまくいきません。
    もし可能でしたら、暇なときにでもお知恵を貸していただけますと幸いです。

  17. Candy より:

    丁寧すぎる解説、、有益すぎます…!!
    解説通り実行したら完成しました!ありがとうございます!

    GASおじさんにご教授いただきたいことがあります。

    今回のフォームとカレンダーに関することなのですが、
    見学日と見学日時を4つほどにフォームを増やし、それぞれの見学日と見学日時にたいしてカレンダーを同期させるなんて方法は出来るのでしょうか?

    当方学習塾を運営しており、月4回のレッスンを実施する候補を1つのフォームで完結できれば利用者様が都度フォームで申請する手間が省けると思い、なにか方法があればご教授いただきたいです。

    なにとぞよろしくお願いいたします!

  18. かわ より:

    初めまして。
    職場でネット予約システムを作ることを任され、プログラミングなど全くわからずいろいろ調べていたところこの記事に辿り着きました。
    とてもわかりやすい解説ありがとうございます。
    一つご質問なのですが、日を跨いだ予定をGoogleカレンダーに登録する方法を教えていただきたいです。
    例えば、
    利用開始日 :2023.8.19
    利用開始時間:11時00分
    利用終了日 :2023.8.21
    利用終了時間:13時30分
    をGoogleカレンダーに登録したいのですが、60分の予定で登録されてしまうので日を跨いだ予定を登録できるコードを教えていただけるとありがたいです。
    よろしくお願いいたします。

  19. 予約次郎 より:

    トリガーがうごきません。
    これはどういタイプのエラーでしょうか?

    TypeError: Cannot read properties of undefined (reading ‘split’)
    at createEvent(コード:8:36)

タイトルとURLをコピーしました