Software tips, techniques, and news.
Have you ever inherited a system built by someone else, changed a field’s name and everything stopped working? The issue, hardcoded names used in indirection, makes the system fragile. FileMaker provides developers many methods to add flexibility using indirection. However when these instances of indirection are not treated properly they will raise all sorts of problems. In this article we will discuss good practices regarding indirection that will help you build a dynamic and robust FileMaker system.
Indirection in FileMaker refers to the ability to reference an object (table, layout, value list, field, script) by its name, instead of its internal id. For example, I can use a few lines of code to tell a script to do something if the user is in field "CONTACT::firstName".
<span class="long-link">If [ Get ( ActiveFieldTableName ) & "::" & ( ActiveFieldName ) = "CONTACT::firstName"]</span> Do Some Code End If
It looks normal at first glance but there are actually two issues with this approach and with many other uses of indirection: The first issue is that if not treated carefully, renaming objects may break indirection. In our example, if I rename the field "firstName" to "first_Name", it will break my script because there are no fields named "firstName" anymore. The second issue is that indirection is not considered as a reference in DDRs. So if you use analysis tools like BaseElements to check where field CONTACT::firstName is referenced, that script will not be included.
With that being said, how do we write robust indirection? Robust indirection will try to dynamically grab an object name and use it in your solution. So we should try to avoid hardcoding the following in our solutions:
Following this guideline, for our example we want to get rid of the hardcoded TO names and field names and instead, dynamically grab the field's name.
<span class="long-link">If [ Get ( ActiveFieldTableName ) & "::" & Get ( ActiveFieldName ) = GetFieldName ( CONTACT::firstName ) ]</span> Do Some Code End If
In this case, if I change the field name to first_Name, that script will still work. Also now field CONTACT::firstName is considered as referenced by this script in DDRs. The magic is being done by the function GetFieldName (). This function actually takes a direct reference to the field and translates it into a name.
However, not all objects in FileMaker have a function like GetFieldName to translate direct references into a name. For example, if I want to have one script perform different activities on different layouts, in order to determine which layout the user is on, it seems unavoidable to use something like:
<span class="long-link">If [ Get ( LayoutName ) = "Contact - Data Entry" ]</span> Do Some Code End If
which suffers from the same problems as the first example: you can't rename your layout and it won't be recognized as a reference in DDRs. What do we do now? Well, in this case it will be hard to solve the second issue. But we can do something about the first issue so we can rename our objects with confidence.
Internally FileMaker assigns an internal ID for every object in the system. When you use script steps like Set Field  and point that to a field, FileMaker will store the ID of the field with that script step. That is why no matter how you rename your field, Set Field  script step will never be broken.
FileMaker has a series of design functions that provide you with information about these internal IDs. With some custom functions built upon them, we can grab the internal ID for any table, layout, value list, field or script and use them in our calculations and scripts. Be sure to try them out in the demo file of this article.
So let's say the internal layout ID for layout "Contact - Data Entry" is 2. With the help of our custom function "getLayoutName" (getLayoutName will take an internal layout ID and translate it to that layout's name). I can rewrite my script to be:
<span class="long-link">If [ Get ( LayoutName ) = getLayoutName ( 2 ) ]</span> Do Some Code End If
This way I can rename the layout and still have the script working. As mentioned before, referencing internal IDs still can not be seen by DDRs as a reference. Also it makes reading the code harder. So be sure to comment your calculation or your script when you use internal IDs to enhance readability. Here is an article if you want to learn more about using internal IDs in your solution.
One last example I want to mention here is about using the ExecuteSQL function. ExecuteSQL is a context independent way to retrieve data. It can save a lot of time when developing complex reports or charts. However ExecuteSQL requires indirection by nature. If not treated carefully, renaming of fields or tables will break the SQL statement used in your ExecuteSQL. In the demo file I included two scripts showing how to use some custom functions to make your SQL statement dynamic and robust.
Now that we have went through two examples of how to write robust indirection, you might want to take a look at your own solution and see if there are any potential problems in there caused by indirection. How do I find all those instances? Use an DDR analysis tool like BaseElements or InspectorPro to search for indirection.
Here are the functions you should be searching for:
and here are the script steps you should be looking for:
Once you find all the instances that could potentially use indirection you can go over each one of them and determine if they uses hardcoded names and should be updated.
Using indirection in FileMaker definitely gives your solution more flexibility, allowing you to accomplish complicated tasks with fewer lines of code. If you follow what we discussed in this article carefully, you should be able to build a dynamic yet robust FileMaker system. Feel free to contact us if you need any assistance with your FileMaker application.
Did you know we are an authorized reseller for Claris FileMaker Licensing?
Contact us to discuss upgrading your Claris FileMaker software.
Weihao is a FileMaker Certified Developer, a creative thinker and a great communicator. He thrives on utilizing his keen technical skillset to solve problems in a manner that will make a positive difference for customers. His passion and drive to demonstrate excellence is evident in all of his work.