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

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

ただいまの
回答率

90.51%

  • Google Apps Script

    1256questions

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

特定のスクリプトを特定のシートにのみ働くようにしたい。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,671

koromo_t

score 50

下記のようなスクリプトを書きました。

下記のスクリプトにおいて、
function onEdit1()はシート「歩数計」のみに働くように、
function onEdit2()はシート「睡眠記録」のみに働くように、
function onEdit3()はシート「10食品群」のみに働くように、
それぞれしたいのですが、
どうも、相互的に?反応してしまうようです。
これを解決するためには、どうすればよいでしょうか。

具体的には、項目ごとにスプレッドシートがあり、
それらの入力用シートだけを集めたスプレッドシートを作ってみたのです。
(IMPORTRANGEを使って、リンクさせている)

よろしくお願いします。

function onEdit(e){
  onEdit1();
  onEdit2();
  onEdit3();
}

// シートに変更があった時に実行する関数
function onEdit1() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("歩数計");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  // 変更のあったセルの値
  var val = cell.getValue();
  // 変更のあったセルの文字列がnだった時に
  if( ( val == "n" ) ) {
    cell.setValue("バンザイなし") ;
  }
  // 変更のあったセルの文字列がaだった時に
  if( ( val == "a" ) ) {
    cell.setValue("バンザイあり") ;
  }
}

function onEdit2() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("睡眠記録");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  Logger.log(cell);
  // 変更のあったセルの有る行番号
  var r = cell.getRow();
  Logger.log(r);
  // 変更のあったセルの有る列番号
  var c = cell.getColumn();
  Logger.log(c);
  // 変更のあったセルの左隣のセル
  var cellLeft = ss.getRange(r, c - 1);
  Logger.log(cellLeft);
  // 変更のあったセルの2つ左隣のセル
  var cell2Left = ss.getRange(r, c - 2);
  Logger.log(cell2Left);
  // 変更のあったセルの値
  var val = cell.getValue();
  Logger.log(val);
  // 変更のあったセルの左隣のセルの値
  var val2 = cellLeft.getValue();  
  Logger.log(val2);
  // 変更のあったセルの2つ左隣のセルの値
  var val3 = cell2Left.getValue();  
  Logger.log(val3);
  // 変更のあったセルが変更のあったセルの2つ左隣のセルの値よりも小さいか、変更のあったセルの左隣のセルの値が空白ではなく、変更のあったセルの値が変更のあったセルの左隣のセルの値よりも小さかった時に
  if( ( ( ( val < val3 ) || ( val2 != "" ) ) && val2 > val ) ) {
    Logger.log( ( ( val < val3 ) || ( val2 != "" ) &&  val2 > val ) );
    // 変更のあったセルの有る行の下の行の2列目を選択
    var rowRange = ss.getRange(r+1, 2);
    // 変更のあったセルの有る行の下の行の3列目を選択
    var rowRangeRight = ss.getRange(r+1, 3);
    // 変更のあったセルに1を入力
    cell.setValue(1) ;
    // 変更のあったセルの有る行の下の行の2列目に0を入力
    rowRange.setValue(0) ;
    // 変更のあったセルの有る行の下の行の3列目に変更のあったセルの値を入力して右隣にアクティブセルを移動
    rowRangeRight.setValue(val).offset(0, 1).activate();
  }
}

// シートに変更があった時に実行する関数
function onEdit3() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("10食品群");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  // 変更のあったセルの値
  var val = cell.getValue();
  // 変更のあったセルの文字列がnだった時に
  if( ( val == "m" ) ) {
    cell.setValue("○") ;
  }
}

~解決後のまとめ~

mix-peachさんの回答を参考に解決しましたので、まとめておきます!


「変更されたシート名を取得すること」、ここがネックだったのですね。
そして、switch文というものに、今回初めて出会いました。条件分岐というのですね。
構造も、知ってしまえばわかりやすくてよいですね! 学習しました。

function onEdit(e){

  //今変更されたシート名を取得 (どう取得できるかはお調べください^^;)
  var edit_sheet_name = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getSheetName();
  Logger.log(edit_sheet_name);

  switch (edit_sheet_name){
    case '歩数計':
      onEdit1();
      break;

    case '睡眠記録':
      onEdit2();
      break;

    case '10食品群':
      onEdit3();
      break;
  }
}

// シートに変更があった時に実行する関数
function onEdit1() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("歩数計");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  // 変更のあったセルの値
  var val = cell.getValue();
  // 変更のあったセルの文字列がnだった時に
  if( ( val == "n" ) ) {
    cell.setValue("バンザイなし") ;
  }
  // 変更のあったセルの文字列がaだった時に
  if( ( val == "a" ) ) {
    cell.setValue("バンザイあり") ;
  }
}

function onEdit2() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("睡眠記録");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  Logger.log(cell);
  // 変更のあったセルの有る行番号
  var r = cell.getRow();
  Logger.log(r);
  // 変更のあったセルの有る列番号
  var c = cell.getColumn();
  Logger.log(c);
  // 変更のあったセルの左隣のセル
  var cellLeft = ss.getRange(r, c - 1);
  Logger.log(cellLeft);
  // 変更のあったセルの2つ左隣のセル
  var cell2Left = ss.getRange(r, c - 2);
  Logger.log(cell2Left);
  // 変更のあったセルの値
  var val = cell.getValue();
  Logger.log(val);
  // 変更のあったセルの左隣のセルの値
  var val2 = cellLeft.getValue();  
  Logger.log(val2);
  // 変更のあったセルの2つ左隣のセルの値
  var val3 = cell2Left.getValue();  
  Logger.log(val3);
  // 変更のあったセルが変更のあったセルの2つ左隣のセルの値よりも小さいか、変更のあったセルの左隣のセルの値が空白ではなく、変更のあったセルの値が変更のあったセルの左隣のセルの値よりも小さかった時に
  if( ( ( ( val < val3 ) || ( val2 != "" ) ) && val2 > val ) ) {
    Logger.log( ( ( val < val3 ) || ( val2 != "" ) &&  val2 > val ) );
    // 変更のあったセルの有る行の下の行の2列目を選択
    var rowRange = ss.getRange(r+1, 2);
    // 変更のあったセルの有る行の下の行の3列目を選択
    var rowRangeRight = ss.getRange(r+1, 3);
    // 変更のあったセルに1を入力
    cell.setValue(1) ;
    // 変更のあったセルの有る行の下の行の2列目に0を入力
    rowRange.setValue(0) ;
    // 変更のあったセルの有る行の下の行の3列目に変更のあったセルの値を入力して右隣にアクティブセルを移動
    rowRangeRight.setValue(val).offset(0, 1).activate();
  }
}

// シートに変更があった時に実行する関数
function onEdit3() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("10食品群");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  // 変更のあったセルの値
  var val = cell.getValue();
  // 変更のあったセルの文字列がnだった時に
  if( ( val == "m" ) ) {
    cell.setValue("○") ;
  }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

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

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

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

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

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

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

Google Apps Script は使ったことがありませんので、その前提でお聞きください。

気になるのは、

function onEdit(e){
  onEdit1();
  onEdit2();
  onEdit3();
}


ここです。

onEditは「どこかのシートのどこかのセルで変更があった時」に呼ばれる処理かと想像していますが、合っていますか?

であれば、
その中でonEdit1 から3まで全て呼んでいるので、いつでも全部が動くのだと思います。

必要なのは、
「今変更されたシート名を識別して、どの関数を呼ぶかを分岐させる」ことでは
ないかな?と思います。

例えば こんな感じ・・・(今適当に書くだけなので、スペルミスなどありましたらご容赦を)

function onEdit(e){

  //今変更されたシート名を取得 (どう取得できるかはお調べください^^;)
  var edit_sheet_name = ’???’;

  switch (edit_sheet_name){
    case '歩数計':
     onEdit1();
      break;

    case '睡眠記録':
      onEdit2();
      break;

    case '10食品群':
     onEdit1();
      break;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/05 09:57 編集

    回答ありがとうございます!
    はい、onEditはそういうイベントハンドラだと思われます!
    なるほど、「変更されたシート名を取得すること」、ここがネックだったのですね。
    そして、switch文というものに、今回初めて出会いました。条件分岐というのですね。
    構造も、知ってしまえばわかりやすくてよいですね! 学習しました。
    おかげさまで、期待通りの結果を得るスクリプトを書くことができましたので、
    回答欄および質問文に追記しようと思います!

    キャンセル

+1

function onEdit1()はシート「歩数計」のみに働くように、
function onEdit2()はシート「睡眠記録」のみに働くように、
function onEdit3()はシート「10食品群」のみに働くように、

上記だけなら、表面上はmix-peachさんの回答に準じて修正を行えば良いように思えます。

しかし、質問内容から全体の構造をイメージするといろいろと矛盾や疑問が生じます。

 スプレッドシートとシート(表現の統一)

経験上、当方がGAS案件を受注する際、クライアント様の要望にて、上記、表現が統一されていないことが多いです。
その際にも前置きしていることですが、以降、スプレッドシート(エクセルで言うブック、以降SS)、シート(同、シート)と明確に区別させて頂きます。

 構造と目的の明確化

質問内容から全体構造を解釈すると、以下のようになります。

  • SS_1(「歩数計」シートを含む)
  • SS_2(「睡眠記録」シートを含む)
  • SS_3(「10食品群」シートを含む)
  • SS_4(各SSの入力用シート、3シート)

GASはSS_4に設定され、IMPORTRANGEで読み込んだ各シートに対し、以下の動作を期待している。

  • SS_4.「歩数計」シートを編集→「歩数計」シートのみ反映(SS_1.「歩数計」シートへの反映を期待?)
  • SS_4.「睡眠記録」シートを編集→「睡眠記録」シートのみ反映(SS_2.「睡眠記録」シートへの反映を期待?)
  • SS_4.「10食品群」シートを編集→「10食品群」シートのみ反映(SS_3.「10食品群」シートへの反映を期待?)

 矛盾点

上記構造であるなら、IMPORTRANGEで読み込んだデータを編集した場合、そもそも「#REF!」エラーになります。
※読み込み範囲外のセルを編集(この場合は追記)した場合は問題ありません。

期待している処理内容が外部SSへの編集内容反映ならば、そもそもonEditでは外部SSの操作不可です。
従いまして、

相互的に?反応してしまうようです。

という内容に矛盾します。

上記、本来は追記・修正依頼に書くべきですが、細かい説明を要するため回答欄に書きました。
当然、当方の質問内容の誤解もございますので、構造と目的が明確になりましたら、必要に応じて提示されたコードを修正・添削させていただきます。

ちなみにですが、onEdit(e)とされていますので、e.sourceでSSオブジェクト、e.rangeでRangeオブジェクト、e.valueで編集後の値を取得できます。(その他の情報も取得可能)

[参考]
Google Apps Script Event Object > Edit

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/05 09:59 編集

    あ、たぶんおっしゃっていることを私も思ったので(というか、作業のなかで判明した?)、
    SS_4内の各「入力用シート」を、SS_1~3内の各「入力用シート」にそれぞれリンクすることで、
    そのあたりは解決したと記憶しています。
    なので、矛盾はしていません。大丈夫です。
    回答ありがとうございます!

    キャンセル

  • 2018/04/05 10:41

    参照方向が逆でしたね。

    > それらの入力用シートだけを集めた
    上記からSS_4への集約と誤解しましたが、SS_4からの各SSへの展開ということですね。

    キャンセル

  • 2018/04/05 10:51

    そうなんです! 私も、最初はそのようにしていたのですが(SS_4への集約)、
    なんかエラーが出たような気がするので、方針を変えたところ、うまくいった次第であります。
    質問文の書き方が適切ではなかったかもしれません、その点はすみません…。
    というか、質問文の「具体的には~」からの、IMPORTRANGEに関する部分は、
    誤解を招くだけで、書く必要がなかったような気がしました。。。
    状況をなるべく詳しく書こうとして、逆効果になったパターンかもしれません。。

    キャンセル

0

~解決後のまとめ~

mix-peachさんの回答を参考に解決しましたので、まとめておきます!


「変更されたシート名を取得すること」、ここがネックだったのですね。
そして、switch文というものに、今回初めて出会いました。条件分岐というのですね。
構造も、知ってしまえばわかりやすくてよいですね! 学習しました。

function onEdit(e){

  //今変更されたシート名を取得 (どう取得できるかはお調べください^^;)
  var edit_sheet_name = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getSheetName();
  Logger.log(edit_sheet_name);

  switch (edit_sheet_name){
    case '歩数計':
      onEdit1();
      break;

    case '睡眠記録':
      onEdit2();
      break;

    case '10食品群':
      onEdit3();
      break;
  }
}

// シートに変更があった時に実行する関数
function onEdit1() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("歩数計");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  // 変更のあったセルの値
  var val = cell.getValue();
  // 変更のあったセルの文字列がnだった時に
  if( ( val == "n" ) ) {
    cell.setValue("バンザイなし") ;
  }
  // 変更のあったセルの文字列がaだった時に
  if( ( val == "a" ) ) {
    cell.setValue("バンザイあり") ;
  }
}

function onEdit2() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("睡眠記録");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  Logger.log(cell);
  // 変更のあったセルの有る行番号
  var r = cell.getRow();
  Logger.log(r);
  // 変更のあったセルの有る列番号
  var c = cell.getColumn();
  Logger.log(c);
  // 変更のあったセルの左隣のセル
  var cellLeft = ss.getRange(r, c - 1);
  Logger.log(cellLeft);
  // 変更のあったセルの2つ左隣のセル
  var cell2Left = ss.getRange(r, c - 2);
  Logger.log(cell2Left);
  // 変更のあったセルの値
  var val = cell.getValue();
  Logger.log(val);
  // 変更のあったセルの左隣のセルの値
  var val2 = cellLeft.getValue();  
  Logger.log(val2);
  // 変更のあったセルの2つ左隣のセルの値
  var val3 = cell2Left.getValue();  
  Logger.log(val3);
  // 変更のあったセルが変更のあったセルの2つ左隣のセルの値よりも小さいか、変更のあったセルの左隣のセルの値が空白ではなく、変更のあったセルの値が変更のあったセルの左隣のセルの値よりも小さかった時に
  if( ( ( ( val < val3 ) || ( val2 != "" ) ) && val2 > val ) ) {
    Logger.log( ( ( val < val3 ) || ( val2 != "" ) &&  val2 > val ) );
    // 変更のあったセルの有る行の下の行の2列目を選択
    var rowRange = ss.getRange(r+1, 2);
    // 変更のあったセルの有る行の下の行の3列目を選択
    var rowRangeRight = ss.getRange(r+1, 3);
    // 変更のあったセルに1を入力
    cell.setValue(1) ;
    // 変更のあったセルの有る行の下の行の2列目に0を入力
    rowRange.setValue(0) ;
    // 変更のあったセルの有る行の下の行の3列目に変更のあったセルの値を入力して右隣にアクティブセルを移動
    rowRangeRight.setValue(val).offset(0, 1).activate();
  }
}

// シートに変更があった時に実行する関数
function onEdit3() {
  // 変更のあったシート
  var ss = SpreadsheetApp.getActive().getSheetByName("10食品群");
  // 変更のあったセル
  var cell = ss.getActiveRange();
  // 変更のあったセルの値
  var val = cell.getValue();
  // 変更のあったセルの文字列がnだった時に
  if( ( val == "m" ) ) {
    cell.setValue("○") ;
  }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • Google Apps Script

    1256questions

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