The While function, introduced in FileMaker 18, makes it easy to perform looping operations in FileMaker calculations without having to create complicated recursive custom functions. It is also more performant and efficient than recursive custom functions. I have found it to be very handy for passing script parameters when writing FileMaker scripts. This helps to consolidate several similar scripts into a single script, which allows me to try to normalize scripting logic.
JSON (Javascript Object Notation) makes a lot of sense to use for Script Parameters, due to its readability and portability. The example shown here builds off of a technique shown here for automatically defining local variables for use in a script, based on JSON data passed into the script.
Simplicity
I am an advocate of keeping things as simple as possible, allowing for more elegant code and reducing the technical debt incurred with more complex methodologies. With that in mind, I only ever pass script parameters with all elements at the top level of the JSON and only as strings.
In general, you should handle variables as text, so if you need to cast your data as a certain type, you can always do that explicitly inside your script. This makes it easy to handle casting values as dates or numbers and add other data validation should you need it.
So, we pass a script parameter as a single JSON object where each element is a name/value pair. This will translate into a local FileMaker variable getting assigned for the “name” and given associated value. Note that the names you designate for the variables are subject to the FileMaker field naming restrictions, so keep the naming convention sensible and simple. The custom function that assigns all variables handles error trapping for misnamed variables.
At the heart of the custom function, we use a While function in the calculation to loop through the JSON properties, dynamically assigning variables along the way. Here is a snippet from the custom function:[/vc_column_text]
While (
[
namespace = namespace;
json_keys = JSONListKeys ( json ; "" );
count = ValueCount ( json_keys );
json_err = "";
this_err = 0
];
( count > 0 ) and ( this_err = 0 );
[
this_key = GetValue ( json_keys ; count );
this_value = JSONGetElement ( json ; this_key );
this_evaluate = "Let ( $" & namespace & this_key & " = \"" & this_value & "\"; \"\")";
this_err = EvaluationError ( Evaluate ( this_evaluate ) );
$json_debug = JSONSetElement ( json_err ; [ this_key ; this_err ; JSONString ] ; [ "json" ; this_err ; JSONString ] );
count = count - 1
];
this_err
)
You can see that we decrement down as we iterate through the top-level JSON keys, starting with the total values present and working our way backward. The EvaluationError function will capture if there was an issue creating the local variable, and the error code is returned to our script. In our sample file, we also use a custom function to show a more meaningful message based on the error code returned. Using the While function also means this technique requires FileMaker 18+.
Writing JSON using JSONSetElement
If you are not familiar with FileMaker’s JSON functions, they are very easy to use. Using the JSONSetElement function takes care of properly forming and escaping any JSON we produce. There is a handy way of writing out this function in the calculation dialog, to make it very easy to add or delete elements as needed.
JSONSetElement ( ""
; [ "action" ; "build" ; JSONString ]
; [ "id" ; $id ; JSONString ]
)
Note that each line with square brackets can be copied and pasted to add another element. The square brackets allow for additional parameters assigned in this FileMaker function. You can use square brackets even if you only have one element to define. There are several FileMaker functions that behave this way, like the Substitute function.
In the above example, the variables that get created will look like the following:
$_action = build
$_id = 123456890
Document Your Variables
This begs the question of how to easily document what variables your script expects and how to easily reference them. There is a small amount of additional overhead to maintain your documentation in these cases, but it pays off when you return to your script months from now and need to figure out what you were doing. Also, code has legs, and it is not uncommon for another developer to have to maintain your code if you ever move on to another project or need to add resources and bring on another developer.
I have taken to noting the variables expected in comments at the top of my script. These tend to add up, and this is where documenting by commenting your scripts helps to keep even long and complicated scripts more manageable. You can see examples in the sample file scripts of how to document the variables that are expected, as well as how to create the JSON like the above function shown here.
Ease of Use
Now, any time you need to pass a script parameter when calling a script, all you need to do is feed it JSON as a parameter. Then in your script, call the custom function in an If script step. If there was an evaluation error, it would return a non-zero result that evaluates as true, in which case you can show a custom dialog and exit the script if you wish. Otherwise, a zero result equates to false, where you can continue in your script.
Setting the $json_debug variable in our custom function as a local variable allows us to access that variable in our script.
Get the Files Used
Sample File
Custom Functions Used
- https://github.com/SoliantMike/FM_Custom-Functions/blob/master/JsonToVars.txt
- https://github.com/SoliantMike/FM_Custom-Functions/blob/master/GetErrorDesc_en.txt
Thanks for this. The simplicity of using While is great.
I have been using this approach of a single script step to create variables from all the top level JSON objects since just before v17 arrived. The majority of posts I have seen about using JSON in the script parameter favour using a separate script step to explicitly create each local variable, so I was pleased to read your post.
I completely agree with only passing script parameter at the top level. However, I do pass JSON data objects in the script parameter and I was very please to see that your custom function passes these through as the contents of one of the variables created.
Nice. I can see how passing objects could be useful. Just tested with Arrays and Objects and both can be passed as parameters.