Meta-Consulting
Meta-consulting is a service Database Pros offers to help other developers
over programming hurdles via GoToMeeting. Email John Mark Osborne or call John Mark at (909) 393-4664 to find out more about this service.
No Relationship Needed Global fields can display in any table within the same file without using a relationship. The same is true between two files in the same solution as long as there is a reference setup between the two files (External Data Source). What a lot of developers do is create a table called "Globals" to house all their global fields and unclutter other Manage Database tables.
The Wedge Claris Corporation and the FileMaker, Inc. have been housed in a building called the wedge in Santa Clara, California since they spun off from Apple, Inc. The building is nicknamed the wedge because it looks like a wedge. For some years they had an adjacent building called the interstitial but it was let go when the company downsized to focus on FileMaker products.
Level: Expert Version: FileMaker 15 Category: General Tuesday, March 21, 2017
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.
What is indirection (and what could go wrong with it)? 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".
If [ Get ( ActiveFieldTableName ) & "::" & ( ActiveFieldName ) = "CONTACT::firstName"] 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.
How to write robust indirection 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:
Table occurrence names
Layout names
Field names
Window names
Value list names
Script names
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.
If [ Get ( ActiveFieldTableName ) & "::" & Get ( ActiveFieldName ) = GetFieldName ( CONTACT::firstName ) ] 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:
If [ Get ( LayoutName ) = "Contact - Data Entry" ] 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:
If [ Get ( LayoutName ) = getLayoutName ( 2 ) ] 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.
How do I identify indirection in my own solution? 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:
Get(LayoutName)
Get(ActiveFieldName)
ValueListItems ( )
Evaluate( )
ExecuteSQL( )
DatabaseNames
FieldBounds( )
FieldComments ( )
FieldIDs( )
FieldNames( )
FieldRepetitions ( )
FieldStyle( )
FieldType( )
Get(ActiveFieldTableName)
Get(ActiveRepetitionNumber)
Get(LayoutNumber)
Get(LayoutTableName)
Get(ScriptName)
GetField( )
GetFieldName( )
GetNextSerialValue( )
GetNthRecord( )
LayoutObjectNames( )
Lookup( )
RelationInfo( )
and here are the script steps you should be looking for:
Set Field by Name[ ]
Go to Layout[ ] (By Name option and By Number option)
Go to Related Record[ ] (By Name option)
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.
Conclusion 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.
This blog is completely free. Please support it by clicking on one of the advertisers at the left side of the window or becoming a patron. Thanks so much!
Comments:
Steve M
05/17/2018
Fantastic Article and great Custom Functions for returning internal layout ID.
I was able to take a script that had to check hard-coded If/Else If statements (about 42 script steps) and drop it down to 3 (Set Variable, Close Window, Go to Layout (Name by Calculation). Thanks again JMO.
Only FileMaker geeks (myself included) get excited about this kind of stuff. You know what I mean. Great to hear this article helped you out. Indirection, adaptive or dynamic scripting is one of the hallmarks of professional design.
Rob
03/28/2017
Hi John Mark, Thanks for putting this blog together. I sincerely appreciate your efforts. FYI, the sample file for "Robust File Design" has a bug in the script attached to the "Show Result" button for the "Bad Example". It returns a "?" instead of a list of contacts. Thought you might like to know. Rob
Thanks so much for the feedback. The sample file has been fixed and uploaded to the site. Happy FileMaking!
Rebecca Johnson
03/24/2017
John Mark you have always been right there with help and direction. Thank you for this WONDERFUL blog.
Richard DeShong
03/24/2017
From a programming best practice, a constant, "This", should be replaced by a variable, This.
For each major function in your system (or even at the individual script level), you can have an "environment setup" script that captures the current names of layouts and such in global variables.
Pedro Rezendiz
03/24/2017
Wow and wooow, thank you very much for sharing those wonderfouls tips. Regards. Pedro
Remote presentations seem so impersonal but I'll give it some thought. I know you have done some remote presentations Beverly. I think it works well when everyone else is on a computer and can interact but when they are in the crowd they seem so removed from the event. Might as well just watch my videos lol.
It's been ingrained in me to watch out for indirection within ExecuteSQL function calls, but I was surprised to learn of the other "gotcha" areas to watch out for. Great eye-opener. Thanks for sharing!
Eric Matthews
03/24/2017
Nice FileMaker Blog!
You should come share it and some of its content at DIGFM.
I would love to visit DIGFM. It's the first place I ever did public speaking. Problem is I live in southern California which is 6 hours away by car. Next time I'm up that way for business, I'll be sure to see if a meeting coincides with my visit.
I use these techniques more and more in my coding. It makes for reliable automation and also really portable functions and scripts that can be lifted and dropped from one solution to another.