Using Filemaker Table Layout Ids In Scripts and Calculations
by Jeremiah Hammond on September 2, 2009
We've all been there: You're going through an existing FileMaker solution, updating data infrastructure to align with the current project's goals and you realize you can't change the '˜Service' table occurrence name to '˜Order' because you've statically referenced the '˜Service' table occurrence name in various scripts and calculations using the built-in FileMaker function Get(LayoutTableName). "Oh well," you say, "I can still change these Service layout names!" Except that you've also statically referenced the layout names with another FileMaker function, Get(LayoutName). Fortunately for you, there's a reliable way to reroute these references:
- Run an HTML Database Design Report (DDR, for short) of the current solution in a copy of FileMaker Pro Advanced.
- Open up the resulting HTML file in a browser of your choice.
- Use the browser's find function to isolate all instances of the word—in your case, 'Service'—and change these instances to use 'Order' if they're the partner-in-crime of a Get(LayoutTableName) or Get(LayoutName) statement (e.g. "Get(LayoutTableName) = "Service"").
Unfortunately for you, this takes time and could result in transcription errors. There's gotta be a better way, right?
No, there isn't. If you've been implementing FileMaker database solutions with references to static/hard-coded table occurrence or layout names, the only way you will be able to change said table occurrence or layout names is to drudge through your solution with DDR in hand and manually change the references to their new names. Then and only then can you feel secure in changing the table occurrence or layout names themselves.
Of course you could just change the table occurrence or layout names and ignore the possibility that things will break if the old names are hard-coded in scripts or calculations. Personally I don't know any developer who would feel comfortable taking that risk.
An Ounce of Prevention
Cures are generally much more tedious to apply than preventions. Using a DDR to change references is a cure. What we really want is a prevention. Is there any way to reference table occurrences and layouts in scripts and calculations as to allow a developer to change names without breaking anything? Why yes there is: Use FileMaker internal IDs.
When you create a new table occurrence or layout (or most any FileMaker object, for that matter), FileMaker references that particular table occurrence or layout internally with an ID. It doesn't use the table occurrence name or the layout name. What this means is that you can always isolate any table occurrence or layout you want if you only knew the corresponding FileMaker internal ID.
Grabbing a List of FileMaker Internal IDs
FileMaker provides a handy-dandy set of what are called design functions that spit out information about the structure of an open database file, information like a list of all field names, script names, etc. in the current file. Included in these functions are functions that list all table IDs and layout IDs in the specified file, each one separated by a carriage return. To illustrate, if you have a FileMaker file with three layouts—Order, Invoice and Contact—with IDs 3, 1, and 2—respectively—using the function LayoutNames(Get(FileName)) will return the three layouts in order of layout number, which is to say, the order in which they are organized under Manage > Layouts :
Contact Order Invoice
Now, the same file will return the following list using LayoutIDs(Get(FileName)):
2 3 1
Notice that the layout IDs are not the same as the layout numbers. In our example, Contact has a layout number of 1 (because it's the top most layout under Manage > Layouts), but a layout ID of 2. Order has a layout ID of 3 but a layout number of 2.
The practical use of all of this is that you want to extract a FileMaker ID from a given table occurrence or layout name and then hard-code that ID into scripts and calculations. The difference between hard-coding a name versus a FileMaker ID is that an ID will never change while a name could change, as you may want to alter the name of a table occurrence or a layout in the future (e.g. our earlier example of 'Service' to 'Order'). The only way an ID will change is if you delete that object and then replace all instances of that object with a new object under the same function and name. Let's say you have an Avery 5160 label print layout called "Avery Labels" with the internal ID of 5 that suddenly becomes corrupted. You delete the corrupted layout and create a new one under the same name. But because this is a new object, the FileMaker internal ID is different than the original layout's ID. For illustration purposes, let's say the new layout's ID is 140. Although this new layout has the same name, same look and same function as the original one, the internal ID is different. Thus, if you hard-coded the original Avery layout's ID in any scripts or calculations, you will have to manually change those references to the new layout's ID, a task which we are trying to avoid by using IDs in the first place. However, the likelihood that you will have a corruption is much, much smaller than the want/need to change names in the future, and so using IDs are still best practice.
Returning to our modest-sized solution of 3 layouts, we want to extract a layout ID from its corresponding layout name. The easiest way to do this is to build a custom function, as you don't want to reinvent the wheel, so to speak, every time you need a layout ID. You can build the logic to extract an ID based on a name once in a custom function and then use the custom function throughout your solutions.
Or, you could borrow someone else's custom function and never have to invent the wheel yourself! We highly recommend you visit Brian Dunning's FileMaker Pro Custom Functions website, not only to extract IDs from names, but also to browse for any other potentially useful functions. We've gotten ourselves out of a few jams copying the free custom functions offered on this site.
In particular, Ulf Carlsson's custom function GetLayoutID("current") will allow you to extract a layout ID of the layout name you pass in the "current" parameter.
Doing It Yourself
Some of you will probably feel the need to build the function yourself. In that case, all you have to know is how FileMaker's design functions LayoutIDs and LayoutNames organize their lists. Both the IDs and names are organized by layout number, and so because you know both lists are organized exactly the same way, all you have to do is find the position of the layout name in the LayoutNames list and use this position to extract the ID from the LayoutIDs list. We'll spare you the gruesome text parsing details, unless you actually want to know exactly how to do this. If so, feel free to contact us.
IDs in Action
Once you have a GetLayoutID([SomeLayoutName]) in place, it's time to put it to use! Because you are replacing instances of Get(LayoutName) with GetLayoutID, you need a way to dynamically determine the layout ID of the current layout. All you have to do is combine the two functions:
This will dynamically return the layout ID of the current layout, which is in the same spirit as dynamically returning the layout name of the current layout using Get(LayoutName) only.
In most cases, you'll be rewriting a Boolean statement such as this:
Get(LayoutName) = "Contact"
So far we know what to replace the left side of the equation with: GetLayoutID(Get(LayoutName)). To get the right side, you'll need to know the ID of the layout you want to hard-code into this Boolean statement. The easiest way to find this ID is to:
- Navigate to that particular layout.
- Open up Data Viewer (Tools > Data Viewer, a feature only available in FileMaker Pro Advanced).
- Click the Watch tab.
- Add the expression GetLayoutID(Get(LayoutName)).
The expression result should be the ID of the current layout, which is the one you want to hard-code. You can then ensure this is the correct ID by running the script in which you used the GetLayoutID function.
Developers Are Human, After All
If someone tries to read the ID code you just wrote, she/he will have no idea what layout that actually is, unlike a name, which usually provides some sort of context. Layout ID 3 means nothing to both you, who just wrote the script, and any developer down the line who reads or rewrites your script. To add a bit of context to your GetLayoutID statement, add a calculation comment with the name of the layout, like so:
GetLayoutID(Get(LayoutName)) = 2 //Contact
The Reverse: IDs to Names
There are times when you want to convert an ID to a name. To do so with layout IDs, you would need to duplicate the GetLayoutID custom function and basically turn the function inside-out: change all uses of layout ID with layout name and layout name with layout ID. Again, the FileMaker design functions LayoutNames and LayoutIDs are sorted in the exact same manner; all you need to do is find the position of the ID or the name you are trying to extract. If you have a layout name and want an ID, you find the layout name position in the LayoutNames list. If you have a layout ID and want a layout name, you find the layout ID position in the LayoutIDs list. Like before, we'll spare you the text parsing details.
Like LayoutNames and LayoutIDs, FileMaker provides design functions for table names and table IDs: TableNames and TableIDs. Unlike LayoutNames and LayoutIDs, TableNames and TableIDs include more than just tables: they are lists of table occurrences. Therefore we have a slightly more complex situation on our hands.
Because TableNames returns a list of TO names ,not plain ol' table names, this basically means that if you have used the function Get(LayoutTableName) anywhere with any hard-coded TO name, you won't be able to change the TO name without breaking something in the solution, unless you change the hard-coded references. What this also means is that you can change the actual table name which the TO is based off of and be safe, UNLESS there is a TO that has the exact same name as the actual table. If so, FileMaker will automatically rename the TO when the table is renamed, and in that case, if you have hard-coded references that haven't been changed, things will break.
Once you understand that FileMaker returns lists of TOs, not table names in their design functions, everything else works exactly like layout IDs. Both TableNames and TableIDs are sorted the same way (alphabetically, in case you were wonderingâ€¦and in case you were wondering further, no two TOs can have the same name) and thus once you know the position in one list, you can extract the corresponding information from the other list. Just duplicate your GetLayoutID custom function and change all references of layout name to table name and layout ID to table ID. Duplicate your new GetTableID(TableName) custom function and reverse the references to table name and table ID to obtain your GetTableName (TableID) function.
Putting It All Together
Using table occurrence IDs and layout IDs in scripts and calculations will allow you the freedom to rename TOs and layouts as you see fit without any logical repercussions. As a FileMaker developer who tries to build solutions as modular as possible, referencing IDs instead of names just makes sense. We all want our get-out-of-jail-free cards: who knows who will be poking and prodding at our solutions 10 years from now or how the solutions will evolve over time. IDs give the flexibility to induce needed and unforeseen change in the future.