By Daniel Wood, 11 February 2012
Script triggers are a great feature in FileMaker that allow you to initiate a script when certain actions occur such as committing a record or leaving a layout. Not only do they run when user initiated, they can also be script initiated by script steps. This can sometimes produce unexpected results and so you may wish for triggers to be disabled. This article presents a very simple and elegant method of suppressing script triggers from firing when initiated by other scripts.
So after writing the entire article and then sitting down afterwards and having a little thing, it became apparent there is in fact a far more elegant solution that follows the same technique as in the article - but without the need for any variables of any type. It will make more sense as you read the article, but for the time being just note that you could simply pass Get ( ScriptName ) as the parameter to the script trigger and check for whether it is empty or non-empty as your test. Anyways onto the article...
Because we are dealing with two types of scripts in this article, we will refer to triggered scripts as T. The main script that is executing will be called A.
Suppressing script triggers is a common issue and one that has had solutions devised in the past which we have used. The conventional method involves setting a global variable at the beginning of script A as a means to tell other triggered scripts T that script A is executing and that they should halt their own execution immediately.
While this method works, it does require a fair amount of maintenance. Not only does the global script variable have to be set in A, but if there are any exit conditions later on in the script, it must be cleared otherwise the global variable will persist with its value when future scripts are run.
You've all seen local variables and almost certainly used them in scripts to store information required during execution. So what does "local" mean? Well, the local variable only exists within the context in which it is defined. In the case of scripts, when you define a local variable then that variable will only exist while that script is running. Once the script ends, the local variable is trashed. The "script" is the context in this case. We tend to think of these as script variables, but they really aren't.
The Set Variable script step does not actually mention at any point that these are script variables, they are local variables.
Are there any other contexts in a FileMaker solution where we might be able to define a local variable? The answer is yes!
Just like the title says, local variables can be defined outside the context of a script. When this is done, the local variable exists and is available to be referenced anywhere in the current file EXCEPT when a script is running. Once a script begins to execute, the context has changed and the local variable is not available until the script ends.
So what do we know so far? We know that if we can set a local variable outside of a script, then this variable will exist only outside of scripts. Conversely we know that when a script is executing, the local variable is unavailable, and so if we try to obtain its value it will return a blank.
What if we define a local variable outside of a script and then pass it to the script T as a parameter. If T is user initiated then the parameter passed will be the value in the local variable.
However if another script A is executing and triggers script T it is going to pass the local variable. Because the context is a script, the local variable is going to be blank and so script T will receive a blank parameter.
Confused? Ok lets break it down....
Part 1: Defining the Local Variable
The first step involves setting a local variable outside of the confines of a script. This is not quite as easy as it sounds. In order to do this we require a calculation to define the local variable, and we require that calculation to evaluate outside of the script.
In this article we are using 2 different examples of where we can place this calculation and have it evaluate outside of a script.
The first place we could define the local variable is within conditional formatting. These calculations are evaluated when a layout renders for the first time and when the layout refreshes thereafter. In this case we have defined conditional formatting but applied no formatting for the calculation - it is merely to define the local variable.
You could place an object on your startup layout (or a number of layouts) that contain this conditional formatting calculation. You need to make sure it is visible on the layout for it to evaluate.
The second possible location is within a custom menu name. If you have a menu item that is used in your custom menus then you can hide the definition of the local variable within the menu name as shown. Custom Menu names are evaluated when layouts load, refresh and when the menu is accessed.
Other possibilities might be to create a calculation field placed on a layout that defines the variable, or modify an existing calculation field on a layout to define the variable.
NOTE: If you use a startup script, be careful because conditional formatting and custom menus are going to evaluate while the startup script is executing, and as such the variables defined will actually become script variables!
The next step involves setting up script triggers. In this example we are using 3 layout-level script triggers.
Each of the T scripts are being passed the local variable defined in Part 1 which we have called $ScriptTrigger.
In the scripts we place a few lines of code to check the script parameter.
If the triggered script T is user initiated then it is being initiated from outside the context of a script. This means $ScriptTrigger exists with a value and as such the script is passed a non-empty parameter. The triggered script T can then execute because it knows a user has caused it to trigger.
If however script A is executing and does something that causes T to trigger then when it tries to pass $ScriptTrigger it is going to pass a blank variable. Remember, $ScriptTrigger only exists outside of a scriptural context! The variable does not exist in script A.
If you are using the script debugger to try this out you may end up with differing results. With debugger enabled, the conditional formatting and custom menu calculations will actually evaluate at some point during the process so that $ScriptTrigger gets defined within the context of script A. This does not occur when the script debugger is disabled.
This technique can very easily be reversed so that you can use script triggers in a way that they are initiated only from other scripts and not when they are user initiated - simply change the check at the beginning of the triggered scripts.
This technique should probably be accompanied by some documentation as to where you are defining your local variable outside of the script context and what the name of that variable is. You should probably also document the technique in the triggered scripts or parameters passed to them. If other developers come along in future and see a local variable being passed to a script, they may wonder what is going on, and could think it is an error and remove the variable!
Please find attached an example file. This file was used for all the screenshots in this article, and is provided to help you fully understand what is going on in this article, and to let you experiment in FileMaker with this solution.