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

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

新規登録して質問してみよう
ただいま回答率
85.46%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

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

Q&A

解決済

1回答

1377閲覧

GASファイルを複製して動作しない原因

dskxxxx

総合スコア1

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

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

0グッド

0クリップ

投稿2021/09/17 07:35

編集2021/09/17 09:05

Google Apps Script(GAS)について質問です。
プログラマさんに作ってもらったGASの組み込んであるスプレッドシートがありまして、そのファイルは動くのですが、そのファイルを複製した所、複製ファイルは動きませんでした。IDなどは複製したファイルのIDに合わせているので、スクリプトの記述自体に問題はないと思うのですが、
GASファイルを複製する場合、それ以外に気を付けねばならないことはありますか?
(実行者の権限等)

<挙動>
①お問い合わせのメールから自動で必要情報を抜き取ってスプレッドシートに転記。
②訪問が決まったら「訪問シート」に情報を転記
③契約になったら「訪問シート」から「契約シートに」に情報を転記

と言った具合です。

①~③までをこれまでは一つのファイル内で実行していましたが、おもくなったので、「①と②」「③」というようにファイルを複製して分割しようとしています。(分割するのは今回が2度目です。)

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/09/17 08:58 編集

「問題となっているスクリプトのコードを全部記載してください」。 また、コピーしたものを実行したとき、ログに何かエラーが表示されていないのでしょうか? 仮にエラーログ等がある場合は、そのログも全部記載してください。 コード中、コピー元から変えた部分については「ここのIDを変えた」等のコメントを追記し変更した部分をわかりやすいように明記してください。 またそのスクリプトはスプレッドシートだけでなくフォーム経由でも使用しているものか、GCPに紐付けてAPIを割り当てているものか、デプロイをしてウェブアプリとして使用しているものなのか、等によっても変わってくると思いますので、具体的な使用シーンの情報を記載してください。 御記載のように、実行権限が絡んでいる可能性がありますが、現状の質問内容だけでは情報が少なすぎて答えようがないと思います。
dskxxxx

2021/09/17 09:04

<挙動> ①お問い合わせのメールから自動で必要情報を抜き取ってスプレッドシートに転記。 ②訪問が決まったら「訪問シート」に情報を転記 ③契約になったら「訪問シート」から「契約シートに」に情報を転記 と言った具合です。 ①~③までをこれまでは一つのファイル内で実行していましたが、おもくなったので、「①と②」「③」というようにファイルを複製して分割しようとしています。今回このように分割するのは2度目なのですが、うまくできていません。 function onEditfunc(e) { const ss = SpreadsheetApp.getActiveSpreadsheet() const activeSheet = ss.getActiveSheet() const configSheet = ss.getSheetByName("設定") //console.log(JSON.stringify(e)) //処理を実行するにあたり、範囲じゃない事が条件 if (e.range.rowStart != e.range.rowEnd) { return } //範囲だったら処理終了 //アクティブシートに条件が設定されているかどうか判別 const refRow = findRow(configSheet, activeSheet.getName(), 1) if (refRow == 0) { return } //設定されてないシートであれば処理終了 //参照列を取得し、編集された列が一致してるか判別 const refCol = configSheet.getRange(`C${refRow}`).getValue() let buf = activeSheet.getRange(1, e.range.columnStart) buf = buf.getA1Notation() if (refCol != buf.substring(0, buf.length - 1)) { return } //指定の列番号じゃなければ処理終了 //条件と一致するか判別 const condition = configSheet.getRange(`E${refRow}`).getValue() if (e.value === undefined) {e.value = ""} if (e.value != condition) { return } //条件と一致してなければ処理終了 //UPD if(configSheet.getRange(`I${refRow}`).getValue() == "以前分割したシート名"){ const differentSS = SpreadsheetApp.openById("以前分割したシートの属するファイル名") var copySheet = differentSS.getSheetByName(configSheet.getRange(`I${refRow}`).getValue()) }else{ <!-----------今回追加した箇所-------------------------------------------> const differentSS = SpreadsheetApp.openById("今回分割したファイルのID") <!-----------------------------------------------------------------------> var copySheet = differentSS.getSheetByName(configSheet.getRange(`I${refRow}`).getValue()) } if (copySheet === undefined) { return } /* //貼り付け先のシートを取得 const copySheet = ss.getSheetByName(configSheet.getRange(`I${refRow}`).getValue()) if (copySheet === undefined) { return } //シートが存在してなければ処理終了 */ //UPD ED //コピーを開始する const copyArray = configSheet.getRange(`G${refRow}`).getValue().split(",") const pasteArray = configSheet.getRange(`K${refRow}`).getValue().split(",") let lastRow = copySheet.getLastRow() + 1 for (let i in copyArray){ let copyCol = copyArray[i] let pasteCol = pasteArray[i] try{ copySheet.getRange(`${pasteCol}${lastRow}`).setValue(activeSheet.getRange(`${copyCol}${e.range.rowStart}`).getValue()) }catch(err){ Browser.msgBox(err) console.log(err) } } try{ //ソート指定があればソートする const sortCol = configSheet.getRange(`M${refRow}`).getValue() let asc if (configSheet.getRange(`O${refRow}`).getValue() == "昇順"){ asc = true }else if(configSheet.getRange(`O${refRow}`).getValue() == "降順"){ asc = false } if (asc === undefined || sortCol == "") { return } //値がなければ処理終了 copySheet.getRange(2, 1, lastRow, copySheet.getLastColumn()).sort({column: copySheet.getRange(`${sortCol}1`).getColumn(), ascending: asc}) }catch(err){ Browser.msgBox(err) } } /* 指定したワードの行を調べる */ function findRow(sheet,val,col){ var data = sheet.getDataRange().getValues(); for(var i = 0; i < data.length; i++){ if(data[i][col - 1] === val){ return i + 1; } } return 0; } ■エラーメッセージ(動作しているファイルでも同様に出ていますが・・・) TypeError: Cannot read property 'range' of undefined onEditfunc @ コード.gs:12
退会済みユーザー

退会済みユーザー

2021/09/17 09:08

まず、元のプログラムでは、onEditfunc に何かトリガーが設定されていませんか? コピー後の方ではそのトリガー設定が外れている可能性があります。
dskxxxx

2021/09/17 10:24

ご返信ありがとうございます。 プログラマさんに作ってもらった元ファイル(動作確認できているテストファイル※以下テストファイル)にはトリガーはないです。本番環境で動かしているファイルには問い合わせメールからスプレッドシートに転記する挙動用にトリガーは使用していますが、今回のテストファイルは動作確認用でありシート間だけの転記なのでテストファイルにはトリガーは設定されていないのだろうと思います。
退会済みユーザー

退会済みユーザー

2021/09/17 11:21 編集

質問における"コピー元のプログラム"である「動作確認できている方のテストファイル」のテスト実行方法について教えてください。 動作確認できている方のテストファイルをテスト実行する際は、エディタ上で「onEditfunc」を実行している、という理解でよろしいでしょうか。 そして、その場合は「 Cannot read property 'range' of undefined」のエラーは発生するが、止まることなくうまく動作している、という理解でよろしいのでしょうか。 仮に上記がすべて正しい場合、テストファイルの正常な動作の詳細について教えてください。 (正常動作するテストファイルについて「onEditfunc」を実行したときに、どのような動作がなされるのか) 上記に誤りがある場合は、テストファイルの実行方法と正常動作について、正しい内容を教えてください。
dskxxxx

2021/09/17 11:39

>動作確認できている方のテストファイルをテスト実行する際は、エディタ上で「onEditfunc」を実行している、という理解でよろしいでしょうか。 >そして、その場合は「 Cannot read property 'range' of undefined」のエラーは発生するが、止まることなくうまく動作している、という理解でよろしいのでしょうか。 それで大丈夫です。スクリプトの上の実行ボタンを押しています。 どのような動作がされるのか、どいうのはどのようにスプレッドシートが動くのか、ということでしょうか?
退会済みユーザー

退会済みユーザー

2021/09/17 11:50 編集

> どのような動作がされるのか、どいうのはどのようにスプレッドシートが動くのか、ということでしょうか? その通りです。 というのは、私の知る限りでは、(「質問文記載のコードが今回問題となっているテストファイルのプログラムの全コード」であるという前提で) onEditfunc を"エディタ上の実行ボタンを押して実行したとき"に 12行目で「 Cannot read property 'range' of undefined」が発生しているのに、その後何事もなく後続の動作が正常に動く、というのはちょっと考えにくいです。 普通は、 Cannot read property 'range' of undefinedのエラーが発生した時点で動作が止まるはずです。 上記のエラーメッセージが出ても正常に動く可能性として、例外処理を噛ませたうえで、Loggerでエラーメッセージを生成しているパターンがあり得ますが、質問文のコードにはそのような例外処理やエラーメッセージ生成部分は一切存在しておりません。
dskxxxx

2021/09/17 11:53

ありがとうございます。 どのように動くのか、言葉では説明しづらい部分があるのですが、 ①今までの挙動 1.スプレッドの各セルにメールから取得した個人の情報が入ります。(一行毎に一人分。名前や電話番号など。その一行の中に進捗の項目の列があります。) 2.例えば太郎さんの進捗列の値を「契約」にした場合、同ファイルの「契約者一覧」のシートに太郎さんの情報が自動で転記されます。 ②今やりたいこと 基本的には同じなのですが、シート間ではなく、ファイル間での転記になります。 「契約者一覧」のファイルに情報が飛ぶイメージです。 ちなみに1.のメールで取得という部分にトリガーを使用しており、その挙動は別のスクリプトで実現しています。
dskxxxx

2021/09/17 11:55

私が詳しくなく恐縮ですが、そもそも「動いている方がおかしい」ということでしょうか?
退会済みユーザー

退会済みユーザー

2021/09/17 12:10 編集

「 onEditfunc を"エディタ上の実行ボタンを押して実行したとき"に、12行目で「 Cannot read property 'range' of undefined」が発生しているのに、その後何事もなく後続の動作が正常に動く」というのが考えづらいです。 想定される可能性として、 ・正常実行できている方のコード(またはその前の大本のコード)では、「onEditfunc」ではなく、「onEdit」という関数名ではないでしょうか? →onEditfincではなく、onEditという関数名ならば、トリガーを設定せずとも、シートに何か入力したり編集するだけで自動的にonEdit関数が実行されます。そしてonEdit関数がシートへの入力等によって自動実行される場合、「Cannot read property 'range' of undefined」エラーは通常発生しません。 質問者さんは、「onEditfuncを実行ボタンを押して実行させると正常に動く」とおっしゃってますが、大変恐縮ですが、それが勘違いである可能性があります。 具体的には、テスト実行の際、「onEditfunc(またはonEdit)を実行ボタンを押して実行させる 」という動作以外に、質問者さんは毎回テスト実行時に別途何かシートに入力するという動作を行っているのではないでしょうか? そのシート入力動作をトリガーとしてonEdit関数の方が正常に実行され、その結果「正常に動いているように見えている」という可能性を疑っております。 (そのような別入力を行っていないのであれば大変失礼いたしました)
dskxxxx

2021/09/17 12:14

ありがとうございます。確かにそうかもしれません。 実はシート間の転記の条件は入力した値を「契約」にすることが発火条件です。 すみません、おっしゃっていただいていることは上記で合っていますでしょうか? 私がプログラムに詳しくないので、すこしかみ砕いていただけると助かります。 今一度確認しました。もう一つプロジェクトがあり、そちらではonEditになっているようです。 こちらの方が動いていたのかもしれません。もう一度テストしなおします。
退会済みユーザー

退会済みユーザー

2021/09/17 12:20 編集

はい。合っております。 コピー後のプログラムの方の「onEditfunc」を「onEdit」という名前に直して試してみて下さい。 テスト実行方法は、エディタ上のボタンから実行する必要はなく、シートの指定されたセルを「契約」に直してみるだけで良いと思います。 もし別のエラーが出た場合は、そのエラーを教えてください。
dskxxxx

2021/09/17 12:29

一旦転記は問題なくできております。ありがとうございます! メールからの取得など、今一度テストします。
dskxxxx

2021/09/17 13:06

すみません、本番環境で0nEditで実装してみましたが、やはり動かないようです。
dskxxxx

2021/09/17 13:18

2つのプロジェクトが相互に干渉しあうということはないですよね??
退会済みユーザー

退会済みユーザー

2021/09/17 13:26

・関数名の先頭は大文字ではなく半角小文字の「o」でなければなりません。(「OnEdit」だと動きません)「onEdit(e)」 とされていますよね? ・ログに何もエラーは出ていないのでしょうか。 >2つのプロジェクトが相互に干渉しあうということはないですよね?? 通常は、相互に干渉しあうということはないはずです。
dskxxxx

2021/09/17 13:26

ちなみにoneditで実行してもTypeError: Cannot read property 'range' of undefinedのエラーが出ますね。。
dskxxxx

2021/09/17 13:32

/** * 依頼者様が複数のファイルにこのプログラムをコピーして使用出来るように極力シートIDなどぱっと見分かりにくいものは使用せずに実装しています。 * author y-r.tokyo */ const onEdit = (e) => { const ss = SpreadsheetApp.getActiveSpreadsheet() const activeSheet = ss.getActiveSheet() const configSheet = ss.getSheetByName("設定") //console.log(JSON.stringify(e)) //処理を実行するにあたり、範囲じゃない事が条件 if (e.range.rowStart != e.range.rowEnd) { return } //範囲だったら処理終了 //アクティブシートに条件が設定されているかどうか判別 const refRow = findRow(configSheet, activeSheet.getName(), 1) if (refRow == 0) { return } //設定されてないシートであれば処理終了 //参照列を取得し、編集された列が一致してるか判別 const refCol = configSheet.getRange(`C${refRow}`).getValue() let buf = activeSheet.getRange(1, e.range.columnStart) buf = buf.getA1Notation() if (refCol != buf.substring(0, buf.length - 1)) { return } //指定の列番号じゃなければ処理終了 //条件と一致するか判別 const condition = configSheet.getRange(`E${refRow}`).getValue() if (e.value === undefined) {e.value = ""} if (e.value != condition) { return } //条件と一致してなければ処理終了 //UPD ST R.Morimoto if(configSheet.getRange(`I${refRow}`).getValue() == "以前分割したシート名"){ const differentSS = SpreadsheetApp.openById("以前分割したシートの属するファイル名") var copySheet = differentSS.getSheetByName(configSheet.getRange(`I${refRow}`).getValue()) }else{ const differentSS = SpreadsheetApp.openById("今回分割したファイルのID") var copySheet = differentSS.getSheetByName(configSheet.getRange(`I${refRow}`).getValue()) //var copySheet = ss.getSheetByName(configSheet.getRange(`I${refRow}`).getValue()) } if (copySheet === undefined) { return } /* //貼り付け先のシートを取得 const copySheet = ss.getSheetByName(configSheet.getRange(`I${refRow}`).getValue()) if (copySheet === undefined) { return } //シートが存在してなければ処理終了 */ //UPD ED //コピーを開始する const copyArray = configSheet.getRange(`G${refRow}`).getValue().split(",") const pasteArray = configSheet.getRange(`K${refRow}`).getValue().split(",") let lastRow = copySheet.getLastRow() + 1 for (let i in copyArray){ let copyCol = copyArray[i] let pasteCol = pasteArray[i] try{ copySheet.getRange(`${pasteCol}${lastRow}`).setValue(activeSheet.getRange(`${copyCol}${e.range.rowStart}`).getValue()) }catch(err){ Browser.msgBox(err) console.log(err) } } try{ //ソート指定があればソートする const sortCol = configSheet.getRange(`M${refRow}`).getValue() let asc if (configSheet.getRange(`O${refRow}`).getValue() == "昇順"){ asc = true }else if(configSheet.getRange(`O${refRow}`).getValue() == "降順"){ asc = false } if (asc === undefined || sortCol == "") { return } //値がなければ処理終了 copySheet.getRange(2, 1, lastRow, copySheet.getLastColumn()).sort({column: copySheet.getRange(`${sortCol}1`).getColumn(), ascending: asc}) }catch(err){ Browser.msgBox(err) } } /* 指定したワードの行を調べる */ function findRow(sheet,val,col){ var data = sheet.getDataRange().getValues(); for(var i = 0; i < data.length; i++){ if(data[i][col - 1] === val){ return i + 1; } } return 0; }
dskxxxx

2021/09/17 13:32

on editのスクリプトは上記です。
退会済みユーザー

退会済みユーザー

2021/09/17 14:04 編集

onEdit関数をエディタ上の実行ボタンで実行した場合は、必ず「TypeError: Cannot read property 'range' of undefined」のエラーが出てしまうはずです。 (シートに何か入力したり編集したりして、onEdit関数が自動実行されるときは通常「TypeError: Cannot read property 'range' of undefined」エラーは出ないはずです。別のエラーは出るかもしれませんが)
dskxxxx

2021/09/17 13:53

わかりました。実行せずに動きを見てみます。
退会済みユーザー

退会済みユーザー

2021/09/17 14:05 編集

あと、シートに「契約」を入力するだけの場合でもうまく動かないという場合、「TypeError: Canno~」とは別のエラーが出ている可能性がありますので、ログを確認してみて下さい。
dskxxxx

2021/09/17 15:37

ありがとうございます。転機自体は再び成功したようです。 元ファイルのoneditには編集時という発火でトリガーがあり、それを実装したら正常に動きました。
退会済みユーザー

退会済みユーザー

2021/09/17 15:55

コメントの3番目に書いていましたが、元の方にトリガーが設定してあったんですね。まあ解決したのならよかったです。
dskxxxx

2021/09/17 16:16

すみません、お手数おかけしました。
guest

回答1

0

ベストアンサー

経緯から察するに、

A: おおもとのコード (SpreadsheetApp.openByIdは使われていない)
B: シートを分割したコード(エンジニアさんが作ったコード)(SpreadsheetApp.openByIdが使われている)
C: Bを複製したもの (SpreadsheetApp.openByIdが使われている)

それぞれで、関数名やトリガーの設定が微妙に異なっていたために、うまく動いたり動かなかったりしたのではないかと思われます。

まとめると、下記です。
・「onEdit(e)」の場合:
トリガーを設定しなくても、シートに何か入力するだけで自動的に実行されます。
また、トリガーを設定しても、この動作自体は変わりません。

ただし、トリガーを設定しない場合、関数内で別ファイル(別のスプレッドシート)を参照することはできません。(SpreadsheetApp.openByIdがエラーになります)

トリガーを設定すれば、SpreadsheetApp.openByIdは正常に実行できます。


・「onEdit(e)以外」の名前を設定した場合(onEditFunc(e)等):
シートへの入力/編集時に自動実行させるには、トリガーを設定する必要があります。

トリガーを設定すれば、SpreadsheetApp.openByIdは正常に実行できます。

投稿2021/09/17 16:37

編集2021/09/17 16:41
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問