質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

解決済

【GAS】エラー TypeError: Cannot read property '0' of undefined

donguriko
donguriko

総合スコア14

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

1回答

0評価

0クリップ

998閲覧

投稿2022/01/22 14:52

編集2022/02/03 23:36

前提・実現したいこと

2つのGoogleカレンダー(カレンダー①、②)があります。
カレンダー①の予定をカレンダー②にコピーさせるGASを作りたいです。

以下の方法でのコピーを試みています。
1)カレンダー①の登録内容をスプレッドシートに書出し
2)書き出した内容を配列で取得し、カレンダー②に予定登録
3)スプレッドシートに「登録済」のフラグを追記

発生している問題・エラーメッセージ

下のエラーが出てしまっています。

TypeError: Cannot read property '0' of undefined getCalendarEvents @ テスト 予定取得20220122.gs:76

該当のソースコード

以下、コード全部記載します。

GAS

function getCalendarEvents() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const mySheet = ss.getSheetByName("転記シート"); const CAL1 = ' ~割愛~ @group.calendar.google.com'; //★転記元カレンダー★ const calendar1 = CalendarApp.getCalendarById(CAL1); const CAL2 = ' ~割愛~ @group.calendar.google.com'; //★転記先カレンダー★ const calendar2 = CalendarApp.getCalendarById(CAL2); const startTime = new Date('2022/01/04 00:00:00'); const endTime = new Date('2022/01/31 00:00:00');  //★あとで修正★  //同期処理の周期  //const syncDays = 14; //endTime.setDate(startTime.getDate() + syncDays); const events1 = calendar1.getEvents(startTime, endTime); //▼転記シートの記載内容をクリアする //最終行(maxrow1)の取得 const maxRow1 = mySheet.getRange(mySheet.getMaxRows(), 3).getNextDataCell(SpreadsheetApp.Direction.UP).getRow(); console.log("maxRow1 " + maxRow1); //getRange(行、列、▲行分、■列分) const myRange = mySheet.getRange(4, 3, maxRow1, 3); console.log(myRange.getA1Notation()); myRange.clearContent(); //▼カレンダーの情報を二次元配列(values)として取得 //<1>空の二次元配列valuesを生成 const values = []; //<2>一次元配列(record)を作成後にpushメソッドで二次元配列valuesに追加 //配列内は「StartTime」「EndTime」「タイトル」が1行分のデータ for (const event of events1) { const record = [ event.getStartTime(), event.getEndTime(), event.getTitle(), ]; //<3>配列(values)内にrecordのデータを追加 values.push(record); console.log(record); console.log("values.length " + values.length); console.log("values[0] " + values[0]); } //▼スプレッドシートに二次元配列(values)のデータを書き出し //getRange(行、列、▲行分、■列分) mySheet.getRange(4, 3, values.length, values[0].length).setValues(values); //転記先カレンダーに登録済の予定を削除する const events2 = calendar2.getEvents(startTime, endTime); for (const event of events2) { event.deleteEvent(); } //▼データ取得範囲の指定 //各種予定のデータ取得範囲の指定  //最終行(maxRow2)の取得 const maxRow2 = mySheet.getRange(mySheet.getMaxRows(), 3).getNextDataCell(SpreadsheetApp.Direction.UP).getRow(); console.log("maxRow2 " + maxRow2); //getRange(行目,列目,●行分,●列分) //起点はセルC4(行4,列3)~L列まで  const eventRange = mySheet.getRange(4, 3, maxRow2 - 3, 3); console.log("eventRange " + eventRange.getA1Notation()); //▼各予定データを配列(myEvent)として取得する const myEvent = eventRange.getValues(); Logger.log(myEvent); for (let i = 0; i < maxRow2 - 2; i++) { let startTime = myEvent[i][0]; let endTime = myEvent[i][1] let title = myEvent[i][2]; calendar2.createEvent(title, startTime, endTime); //▼転記結果をスプシに追記する //getRange(行、列、▲行分、■列分) console.log("myEvent.length " + myEvent.length); console.log("myEvent[0] " + myEvent[0]); mySheet.getRange(4, 6, myEvent.length ,1).setValue("登録済"); } }

試したこと

エラーが立ってしまっているのでどこかに問題があると思うのですが、
下を見ると1)の処理、2)の処理 3)の処理ともにできているように見えます。

<カレンダーイメージ> 
赤 :転記元カレンダー
黄色:転記先カレンダー
イメージ説明

<スプレッドシート「転記シート」イメージ>
イメージ説明

<<教えてほしいこと 3点>>
知識不足で申し訳ありません。

①誤りの箇所、どのように修正すればよいのか
上記アドバイスをいただけないでしょうか?
どこかの定義ができていないというエラーかと思うのですが、
現コードのどこに誤りがあるのか、分かりません。

②予定コピーの手法
今回、カレンダー①→スプレッドシート→カレンダー②と経由させて
予定コピーをする手法にしました。
が、別アプローチとして、
カレンダー①→カレンダー②にダイレクトにコピーする方法も可能
でしょうか?
可能な場合、「スプレッドシート」経由と「直接方式」どちらの方が
おすすめでしょうか?
その理由(メリ、デメ等の考え方)も教えていただけると助かります。

③「直接方式」が可能かつ「おすすめ」の場合
カレンダー①の予定取得時に使用したvaluesをそのまま使用して、
カレンダー②に予定登録させる方法でできますか?
そのまま使用がNGの場合、どのようなアプローチがよいかの
アドバイスも欲しいです。

(背景)
現在、Googleカレンダー(アドレスに紐づくメインカレンダーと
いくつかのグループカレンダー)を使用しています。
Googleカレンダーの予定を別の予定管理アプリに同期させ、
外出時の予定確認時等で使用したいです。
別の予定管理アプリ(or Googleカレンダーアプリ)とアドレスに紐づく
Googleメインカレンダーの同期はできていますが、セキュリティの
関係なのかGoogleグループカレンダーと別の予定管理アプリの連携が
できず困っています。
そのため、GASで定期的にグループカレンダーの予定を連携可能な
Googleメインカレンダーに自動コピー、別の予定管理アプリとの
連携が実現できないか、を模索したい次第です。

補足情報(FW/ツールのバージョンなど)

回答は急ぎません。
お忙しいところ大変申し訳ありませんが、非エンジニアビギナーでも
わかるレベルでのアドバイス、解説をいただけると大変助かります。

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

itagagaki

2022/01/22 15:31

Logger.log(myEvent); で何が表示されているか、わかりますか? ログの中でこれを見つけるのは難しそうな気もするので Logger.log("myEvent="+myEvent); のようにして実行してみたほうがいいかもしれません。 また、Logger.logではなくconsole.logのほうがいいかもしれません。
donguriko

2022/01/23 00:53

itagagakiさま コメントありがとうございます。 console.log結果~下に掲載します console.log("myEvent " + myEvent);       ↓ myEvent Tue Jan 04 2022 10:00:00 GMT+0900 (Japan Standard Time),Tue Jan 04 2022 10:30:00 GMT+0900 (Japan Standard Time),テスト1,Wed Jan 05 2022 10:30:00 GMT+0900 (Japan Standard Time),Wed Jan 05 2022 11:00:00 GMT+0900 (Japan Standard Time),テスト2,Thu Jan 06 2022 11:00:00 GMT+0900 (Japan Standard Time),Thu Jan 06 2022 11:30:00 GMT+0900 (Japan Standard Time),テスト3,Fri Jan 07 2022 11:30:00 GMT+0900 (Japan Standard Time),Fri Jan 07 2022 13:00:00 GMT+0900 (Japan Standard Time),テスト4,Mon Jan 10 2022 09:30:00 GMT+0900 (Japan Standard Time),Mon Jan 10 2022 10:00:00 GMT+0900 (Japan Standard Time),テスト10,Tue Jan 11 2022 10:00:00 GMT+0900 (Japan Standard Time),Tue Jan 11 2022 11:00:00 GMT+0900 (Japan Standard Time),テスト11,Wed Jan 12 2022 10:30:00 GMT+0900 (Japan Standard Time),Wed Jan 12 2022 11:00:00 GMT+0900 (Japan Standard Time),テスト12,Thu Jan 13 2022 11:00:00 GMT+0900 (Japan Standard Time),Thu Jan 13 2022 11:30:00 GMT+0900 (Japan Standard Time),テスト13,Fri Jan 14 2022 11:30:00 GMT+0900 (Japan Standard Time),Fri Jan 14 2022 12:00:00 GMT+0900 (Japan Standard Time),テスト14 ■不勉強で恐縮ですが、教えてください。  「Logger.logではなくconsole.logのほうがいいかもしれません。」の理由を教えていただけますか? こういう時はこっちがいい等、両者の違いが何か、どう使い分ければいいのかがよく分からず。
itagagaki

2022/01/23 01:11

少なくとも、その実行時の myEvent は undefined ではないようですね。 私の勘ですが let startTime = myEvent[i][0]; で、myEvent が undefined だったため TypeError: Cannot read property '0' of undefined となったのではないかと推測しています。 プログラムを実行して、このエラーメッセージが出力される直前の console.log("myEvent " + myEvent); の出力をもう一度確認してみてください。 Logger.logはトリガーで実行したときにはログに出力されません。 cosole.logなら、トリガーで実行したときもスクリプトエディタで実行したときも出力されます。 なので私はたいていconsole.logを使います。 ただLogger.logには書式が使えるという利点があります。
donguriko

2022/01/23 01:20

itagagakiさま ご返信ありがとうございます。 トリガー設定はまだしていません。 コードを記載する画面? の「実行ボタン」を押して動かしてます。 掲載したのはその時のログです。 そして、今回も又一見ただしく動いてそうにみえるのですが下のエラーが立ちます。 (以下、実行ログ画面から転載)            ↓ TypeError: Cannot read property '0' of undefined getCalendarEvents @ テスト 予定取得20220122.gs:76
donguriko

2022/01/23 01:49

qnoirさま お忙しい中、丁寧な解説、本当にありがとうございます。 エラーの意味と読み方? とても勉強になります。 配列の理解、まだ 消化しきれていないですね。 いただいた回答を再度じっくりと読み返し、理解を深めたいと思います。 又、直接方式と経由方式についても考え方を教えていただきありがとうございます。 メリ、デメ、とてもよく分かりました。 いつも丁寧なご指導本当にありがとうございます。 qnoirさまの丁寧なご指導に報いるべく、頑張って知識を深めたいと思います。 ありがとうございました。
donguriko

2022/01/23 07:32 編集

qnoirさま ご回報内容熟読させていただきました。 「配列は0はじまり」がまだ身についていない事、痛感しました。 慣れるまではコード記載する際、頭が混乱しないよう余白に連番をふる などの工夫をして感覚を身につけていきたいと思います。 2点追加で質問です。 ①修正案2 について - mySheet.getRange(4, 6, myEvent.length ,1).setValue("登録済"); + mySheet.getRange( i + 4, 6, 1, 1).setValue("登録済");  「 i + 4」とすることで、エラーで処理がとまった場合、エラー後はPGMで iを取り?に 行けず、その結果、転記処理も止まるので、コードをiとした方がよい、 という理解であっていますか? 勉強になりました。 ②処理1)カレンダー登録情報を配列として取得する部分のコード 恥ずかしながらこの部分のコードはWEBで参照したコードを自分なりに 読み解き、コメント追記しながら流用させていだきました。 が、何故、以下の3stepをふんで二次元配列にしている(しないといけない)のか、 正直消化不良気味です。 a)空の二次元配列の箱valuesを作る b)カレンダー登録情報を一次元配列recordとして取得 c)二次元配列の箱valuesに一次元配列recordを投入。 スプレッドシートで書き出ししたい形式が二次元なのに対し、 カレンダー登録情報は一次元となっているため、一次元→二次元にするために まずa)の箱を作っておき、pushでそこにデータをいれている、という イメージですか? 回答は急ぎませんので、お時間ある時にレクチャーいただけると助かります。 お手を煩わせて申し訳ありません。
qnoir

2022/01/24 01:24

ご質問の件、私の回答のコメントの方に回答しました。確認宜しくお願いします。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。