見出し画像

#46 トリガーの「編集時」と「変更時」の違いは?

今回の記事は、記事の内容が直接役立つものではなく、この内容によって GAS がより理解できるようになる、もしくは GAS でのプログラムを作成するためのアイディアとなるものです。
そのため、ちょっと小難しい内容となっています…

トリガー設定時のイベントは 4種類?

Google スプレッドシートで GAS(Google Apps Script)のトリガーを設定しようとすると、選択肢には下図のように 4つ表示されています。

「イベントの種類を選択」の選択肢
  • 起動時

  • 編集時

  • 変更時

  • フォーム送信時

この 4つに加えて、「Time-driven (clock):時間駆動型 (クロック)」を含めたトリガーが、「Installable Triggers :インストール可能なトリガー」と呼ばれるようで、以下の URL で説明されています。

トリガーには、「Installable Triggers :インストール可能なトリガー」の他に「Simple Triggers:シンプルなトリガー」があり、この分類については「Simple Triggers」→「Available types of triggers」に説明されています。

Available types of triggers (抜粋)

この表の右側「Installable Triggers」に「Sheets(スプレッドシート)」のアイコンが 4つ並んでいます。これが冒頭のイベントの種類として表示されていた 4つに対応するものです。

  • Open → 起動時

  • Edit → 編集時

  • Change → 変更時

  • Form submit → フォーム送信時

Installable Triggers と Simple Triggers の違い

前述の表を見ていて感じるのは、

  • Installable Triggers と Simple Triggers は何が違うの?

  • スプレッドシートのアイコンが Open と Edit の両方に表示されているのはなぜ?

といったところです。前述のリファレンスに書かれている内容から解釈するに、以下のような感じのようです。

  • Simple Triggers

    • onOpen() や onEdit() のように、あらかじめ決められた名前でトリガー関数を記述する。→ トリガー関数の関数名は予約済みとなっている。

    • 関数名として予約されているので、設定しなくてもトリガー関数として動作する。

  • Installable Triggers

    • 任意の名前でトリガー関数を記述できる。

    • 手作業もしくはプログラムによってトリガー関数として設定しなければ、トリガー関数として動作しない

すなわち、前述の Open と Edit のトリガーは、Installable Triggers としても、Simple Triggers としても動作させられます。

Open を例にすれば、onOpen() という関数名でトリガー関数を記述すれば、冒頭の画像のようにトリガー関数を設定しなくても、トリガー関数として実行されます。別の関数名でトリガー関数を記述した場合には、トリガー関数として設定すれば、トリガー関数として動作します。この設定が、「インストール」ということなのでしょう。

スプレッドシートにオリジナルのメニューを追加するときに、onOpen() をトリガー関数として登録しなくても、スプレッドシートを開いたときに自動的に実行され、メニューが追加されていたのは Simple Triggers として動作していたからです。 ※これまで意識していませんでしたが、何だかすっきりした感じです。

オリジナルのメニューを追加する例

Simple Triggers の制限

ただし、「Restrictions:制限」でも説明されているように、Simple Triggers として動作する場合には、ユーザーに承認を求めることなく自動的に起動されるものの、いくつかの制限が設けられています。

注意が必要なのは、承認(ユーザー認証)が必要な処理は、Simple Triggers としては実行できないことです。
そのため、onOpen や onEdit のように Simple Triggers として動作可能なものであっても、承認が必要な処理を行う場合には、Installable Triggers として動作させなければならないのです。
わかりやすくするなら、以下のような感じで考えてもいいのかもしれません。

  • どちらでもいい場合には Simple Triggers ではなく、Installable Triggers として設定する。 明示的にトリガー関数として設定する。

  • onOpen 以外は、Installable Triggers として設定する。

Edit と Change の違い

冒頭の図にもある、イベントの種類として設定できる Edit(編集時)と Change(変更時)にはどのような違いがあるのかを確認してみました。

具体的には、以下 URL のようにトリガー関数に引数として渡される「Event Objects」が、それぞれのトリガー関数によって異なる内容になっているようで、その内容を比較すれば違いがわかりそうです。

  • Change(変更時)

    • authMode
      A value from the ScriptApp.AuthMode enum.

    • changeType
      The type of change (EDIT, INSERT_ROW, INSERT_COLUMN, REMOVE_ROW, REMOVE_COLUMN, INSERT_GRID, REMOVE_GRID, FORMAT, or OTHER).

    • triggerUid
      ID of trigger that produced this event.

    • user
      A User object, representing the active user, if available (depending on a complex set of security restrictions).

  • Edit(編集時)

    • authMode
      A value from the ScriptApp.AuthMode enum.

    • oldValue
      Cell value prior to the edit, if any. Only available if the edited range is a single cell. Will be undefined if the cell had no previous content.

    • range
      A Range object, representing the cell or range of cells that were edited.

    • source
      A Spreadsheet object, representing the Google Sheets file to which the script is bound.

    • triggerUid
      ID of trigger that produced this event (installable triggers only).

    • user
      A User object, representing the active user, if available (depending on a complex set of security restrictions).

    • value
      New cell value after the edit. Only available if the edited range is a single cell.

似たような名前のトリガー関数でありながら、「Event Objects」の内容はずいぶん違います。

  1. authMode、triggerUid、user、の 3つはどちらにもある。

  2. Edit には、編集された前後の oldValue と value がある。
    Change には、 changeType があり、どのような変更を加えられたかがわかる。

  3. Edit には range があり、どこが編集されたかがわかる。
    Change にはない。

実際に確認してみた!

以下のようなプログラムを作成してみました。それぞれのトリガー関数が実行されたら、対応するセル(B1 か B2)に実行された日時と、状況を記録します。
onEdit() の方は、Simple Triggers として動作させられるので、トリガーとして設定しなくても動作しました。onChange() の方は、Installable Triggers なので手作業でトリガー関数として設定しています。

function onEdit(e) {
  var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var answerSheet = spreadSheet.getSheets();

  answerSheet[0].getRange('B1').setValue('Last modified: ' + new Date() + ' / ' + e.range.getA1Notation() + ' (' + e.oldValue + '→' + e.value + ')');
}

function onChange(e) {
  var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var answerSheet = spreadSheet.getSheets();

  answerSheet[0].getRange('B2').setValue('Last modified: ' + new Date() + ' / ' + e.changeType);
}

上記の GAS のプログラムを、「拡張機能」→「Apps Script」でエディタを開いて、貼り付けます。前述したように onChange() の方は、手作業でトリガー関数として設定します。 ※A1 には「onEdit(event)」、A2には「onChange(event)」と入力してあります。

そして、スプレッドシートで適当に入力を行うと、プログラムで記述されているように B1 と B2 にトリガー関数が実行された状況が記録されます。

onEdit と onChange の違い

実際に実行してみて気付いたことは…

  • 同じようなプログラムなのに、Simple Triggers として実行されている onEdit() では「日本標準時」と表示されていますが、Installable Triggers として実行されている onChange() では「Japan Standard Time」と英語表記になっている。

  • onEdit() を Installable Triggers として登録すると、「日本標準時」ではなく、「Japan Standard Time」と英語表記になった。

  • onEdit() を Installable Triggers として登録すると、Simple Triggers として実行された後に、Installable Triggers としても実行され、2回実行されることになる。 ※Simple Triggers を Installable Triggers として登録するなら、関数名は変更するべき!

  • Event Objects」の内容が違うように、トリガー関数が動作するタイミングと得られる情報には違いがある。

という感じでした。

まとめ

似たような名称の「Edit(編集時)」と「Change(変更時)」という 2種類のトリガー関数は、名前が違うように動作も異なっていました。

  1. 「Edit(編集時)」のトリガー関数は、Simple Triggers と Installable Triggers のどちらとしても動作できる。
    onEdit() という関数名であれば、Simple Triggers として動作するが、Installable Triggers としても登録すると二重に動作してしまうので注意!

  2. 「Edit(編集時)」は、セルの中身が変更されたことを確認、「Change(変更時)」は、シートに対して行われた変更を確認、という感じ。

この二つをうまく使い分けて、いい感じのプログラムを作れればいいな、と思います。 ということで、トリガー関数について詳しくなれたものの、実質的な成果物はありません。

この記事が気に入ったらサポートをしてみませんか?