Software tips, techniques, and news.
A common user interface problem encountered during development of a FileMaker database solution is maintaining the user's current found set when performing scripted finds on the TO of the found set. Imagine a scenario in which a user, already looking at a found set of Invoices, wants to run an accounts receivable report, which performs a find on the same TO. If, during the report script, the find returns no records, the script will most likely inform the user that there are no accounts receivable and set her/him back onto the layout she/he started at before running the report, except unlike before, the user is stuck in a found set of zero. This isn't exactly user-friendly.
There are a couple of ways of solving the found-set-of-zero dilemma. In the report script, before entering find mode, you could loop through all records in the current found set and store their primary keys—each delimited by a carriage return—in a global field in the table tied to the TO which you will perform the find on. Then using a multi-line key relationship, set the global field containing all the primary keys equal to the primary key of the same table. After a find returning no records, perform a Go To Related Record script step based on the multi-line key relationship to restore the pre-find found set. Easy. Except that in a found set of 200,000 records, you might take a speed hit looping through every... single... record. With the speed of technology ever-increasing, the last thing you want to do is sacrifice a significant amount of speed for an albeit important UI face-lift. If the only option you had were looping to restore a found set but you weren't willing to suffer your users, you could kludge your way to a semi-solution by showing all records if the find returns a found set of zero. All is better than none, especially when your interface looks like a piece of swiss cheese when no records are showing.
The rate-limiting step of saving and restoring a found set using record looping is—you guessed it—the looping through each record! For whatever reasons, Filemaker performs exceptionally faster when running calculations than it does running certain script steps, especially when navigating from record to record. Thus to side-step the record-to-record navigation when saving a found set, you'd need to find a way to grab a list of all the records' primary keys in a calculation without navigating record-to-record. One approach is to use a recursive custom function that loops through all the records in the found set, calling itself over and over until it has compiled a list of all primary keys.
In our case, the keystone of the recursive custom function is the built-in Filemaker function GetNthRecord(). This function returns the contents of the field you specify of the record in the current found set that you specify. So if the second Invoice record in the current found set contains the value 5.77' in the field 'Total', GetNthRecord(Invoice::Total, 2) returns 5.77. You can see that if you know the total number of records in the found set, via the Filemaker function Get(FoundCount), then you can build a recursive custom function, one that would accept four parameters:
You can even pass the field name dynamically via Filemaker 10's new function GetFieldName.
Restoring the found set is the same as before: use a multi-line key relationship, where the list of primary keys is stored in a global field.
Of course, this method, like the previous one, will return the user to the first record in the found set, instead of to the record she/he was viewing before the find. To return to the pre-find record, you would have to store the record's primary key in a variable and then use record looping after the found set has been restored to navigate to the right record. Thus you end up stuck in the same dilemma as before, as the found set of records to loop through could be quite substantial. Even if looping through records were lightning fast, you have one other problem to contend with: the restored found set may not have the same sort order as the original. Filemaker pretty much sucks when it comes to saving and restoring sort orders, so you don't really have any room to maneuver here. Fortunately there is one other method of saving and restoring found sets that does restore sort order.
Not only does using different table occurrences to save and restore found sets maximize speed, but it maximizes usability. Here's how it works:
Viola. Not only is the pre-find found set restored, but also the user is on the record she/he was on prior to the find and the sort order is maintained. This method really has only one user interface faux pas: the front tabs of all the tab controls reset to their default values when returning to the pre-find layout. That's another topic for another day.
You're probably wondering why using two different table occurrences tied to the same table enables you to seamlessly save and restore found sets. The short answer is that Filemaker saves found sets based on TOs, not on tables. Each layout is tied to a TO, not to a table. Layouts are the primary user interface in Filemaker, and as such, are used as the foundation upon which to store interface information, such as that of found sets and front tabs.
The most unintuitive part of using two different TOs is the Go To Related Record steps, both when saving and when restoring. It's not entirely obvious why the step even works in the first place, since your two TOs are not tied to each other via a relationship. Somehow, behind the scenes, Filemaker assumes that each record is related to all others in the found set by virtue of being in the same table. We aren't exactly sure why this works, and although we'd like to know for curiosity's sake, we're happy enough that we have a very fast and reliable way to save and restore found sets.
Restoring the found set for a user is nothing more than meeting the user's expectations. Who would ever want to be thrown out of context (i.e. in a found set of zero) after selecting a report to run? I sure wouldn't. I want to be in the exact same situation as I was before selecting that report. I don't want to waste 5 seconds bewildered at why the screen looks essentially blank with no record data. And expecting this behavior is even worse. We strive to build solutions that work the way the user does, not the other way around.
The ultimate solution to the save, restore found set problem would be one in which Filemaker builds a new script step, something akin to Go to Layout (Original Layout), like a Restore Original Found Set. Or even a duo package where you save a TO's found set and then restore that TO's found set, just like we're doing now. Regardless, Filemaker really should have a way to save and restore TO found sets on the script level, and it shouldn't have to require opening a new window.
Of the three methods of saving and restoring found sets in Filemaker, the one that outshines the others by far is using a different TO based on the same table as the TO you want to save the found set of. Looping through records is way too slow for any moderately-sized system, and using a recursive custom function—while fast—doesn't return the user to the record he/she was on, and the found set may not be in the original sort order. For the best user experience, maximum speed and quick implementation, using a different TO to save and restore a found set is the way to go.
Jeremiah is a Certified FileMaker and Salesforce Developer who has been with DB Services since 2007. A Purdue University graduate, Jeremiah earned dual bachelors in Chemistry and Philosophy while simultaneously learning FileMaker. His educational background and natural smarts gives him the ability to be successful both in the trenches of scripts as well as in collaboration with co-workers and clients. A rarity, indeed.