Sub-summary Only Layouts
Last month, I presented for the FileMakerSTL Meetup Group on Layouts Using Only Sub-Summary Parts. In this blog post, I’ll summarize what I talked (a lot) about. The slides for the presentation are available here; the demo file which contains all of the examples I used, during the presentation, and in this blog post, is available here. The demo file was designed to run on either a desktop or an iPad. It also contains more stuff than what I cover in this blog post. Have fun exploring!
The Basic Concept
The basic concept comes from Chiyoko Yoshida’s blog from 2011, Peek a Boo Body Report Technique. My boss pointed me to the article when I first started here at SK; it blew my mind. The idea is that you can:
- create a list view layout
- remove the body part
- add sub summary parts that show summaries of each level you wish to display
- when you want to show data that you would normally show in a body part, include a sort criteria that will group that “body” data by a value that uniquely identifies each data group
That last part can seem a bit cryptic; but, it’s actually pretty simple. Ask yourself: what uniquely identifies the data that I want to show in my ‘body’ part? Take, for example, this list of records for contact information made up of emails and phone numbers: If you were to build a regular sub-summary list layout, you would make Contact information the layout’s context; show the `Value` field in the body part; and, make a sub-summary part that uses `Type` as the break field and shows the `Type` field on the actual sub-summary part. This would be correct. If you wanted to show the same list view layout, but without the body part, you would just need to add another sub-summary part beneath the `Type` part, and that new sub-summary part would break against the `ID` value. Since the value of `ID` is unique to every record, you would end up with a sub summary part showing for each `Contact Information` record. Now, our layout becomes programmatically dynamic. If we wanted our layout to show only the types of contact information available, we could sort by just the `Type` field: Or, if we want to show both the types and the contact information we can sort first by `Type` and then by `ID`: With the same layout, we could show only the contact information by removing `Type` from our sort order and only using `ID`: So, using this technique, we can very easily use the same layout to show different kinds of information just by changing the sort order.
It’s great that you can show these records and programmatically change the layout display, Now, lets make it better by adding in navigation. To navigate through these records you need to do two things:
- Control your found set
- Control your sort order
Let’s look back at our earlier example of Contact Information Types and Values. Let’s turn the Type sub-summary part into a button so that when we tap it, we are shown the sub-summary part for that type and all of the related ContactInformation values that have that specific type. E.g., if we tap on “Email” we’ll see the “Email” type sub-summary and only email addresses under it. We already know that if we add a button to the part that sorts by `Type` and then `ID` we’ll be able to see the values, but we see ALL of the values including the Phone `Type` sub-summary part and the Phone values. If we have that button fires a script that first finds only `Contact Information` records of the type `Email` and THEN sort by `Type` and `ID` we will see just our Email heading and email Values. Our navigation script would look like this: And the script call from our button looks like this: Now we’re controlling our found set by performing a find for only the values we want and we’re controlling our sort by specifying the sort order that will show the sub-summary parts that we want to see.
Something that I try to aim for when using this kind of a layout setup (and that I try to aim for in general when I write scripts) is to write scripts that are stateless. If you’re familiar with the concept of ReST then you already understand what I’m getting at. If not, here’s what I mean by stateless: To achieve stateless actions with a script you need to pass the script all of the criteria it needs to do it’s task so that it does not depend on the triggering layout’s context to get any information. The script does not require the file to be in any particular state ( specific layout, found set, mode, etc) for it to operate. Again, kind of cryptic but simple to understand. Let’s again use our `Contact Information` example, but let’s throw in two extra layers of information: Companies and People. Now that we have related Companies and People, we can show extra layers of groupings in our layout. I’ve added two more sub-summary parts to our layout; one that breaks by the `Company::ID` field and one that breaks by the `People::ID` field: We also have buttons on each of the sub summary parts (except the bottom) that call scripts to show related information. The buttons call scripts and pass in all of the criteria to find the related data , and really, it’s not a lot of data. Take the People sub-summary part and it’s button as an example. When we sort the layout by `Company::ID` and `People::ID`, we will end up getting two sub-summary headings showing each of our companies and then under each we will see a sub-summary part for each of the people that belong to the company, our current “body” part. If from here we wanted to look at a particular person and show both the company that they belonged to and all of their contact information, what is the criteria we actually need to get our found set? Well, when we tap on the name “Chris Schmitz”, we know that the record behind the People sub-summary is for a `ContactInformation` record related to “Chris Schmitz”‘s person record so we can pass in the `People::ID` field. Technically, we could pass in the `ContactInformation::ID_People` foreign key and accomplish the same thing. With the ID value of the People record, we can perform a find for all `ContactInformation` records with that `ID_People` which would limit our found set to just that person’s ContactInfomation. From these records we know we can look up the relationship graph to the `Company` and `People` table occurrences to see the related Company and Person record. With our found set narrowed down, we can safely sort by `Company::ID`, `People::ID` and then `ContactInformation::ID` to show each level of data we want to see. That’s a bit of a mouth full, so let’s look at the screen shots. Here’s the script call from the People sub-summary button: Here’s the script: The structure of this script is pretty much the same as our first example’s script; get the data passed in to the script, perform a find using that criteria to limit our found set, and sort the records according to the break fields that are needed to show each of the sub-summary parts we want to see. In this case we want to see the sub-summary parts for Company, People, and ContactInformation. Since I’m passing in the criteria needed for the script to perform all of it’s tasks, that means I can call this script from anywhere in the file. I could call this exact same script from a layout that uses a completely unrelated table in preview mode and as long as I pass in the `People::ID` for the record I want to find the script will still take me to the layout, perform the find, and display the records correctly.
Different parts for different functions
Another interesting advantage that the concept of sub-summary only layouts offers is being able to create different sub-summary parts for different functions. Let’s use our last example and tweek it a bit. I want to add a sub-summary part for editing Company records and a different sub-summary part for displaying them in a read-only manner. To do this, I’ll create a duplicate of the field that will uniquely identify my company, the `Company::ID` field: Here’s what the layout parts look like: Now, we can use the same found set of records to show completely different parts for the same unique grouping just by picking which fields we sort by. If we sort by `Company::ID` we see just the heading: If we want to show our heading AND the edit sub-summary part, we can sort by `Company::ID` and `Company::ID_EDIT`: And finally, if we want to show our heading AND the display sub-summary part, we can sort by `Company::ID` and `Company::ID_DISPLAY`: Now with EDIT and VIEW buttons on the sub-summary part, we can call separate scripts that do exactly what our scripts before have done; accept the search criteria, find the records, and sort according to break fields that will show our parts. The only difference between the EDIT script and the VIEW script is the sort order. The edit sort: The Display sort:
Just because you CAN doesn’t mean you SHOULD
I would caution anyone who is trying to apply this approach to think about whether or not your list view warrants this kind of a sub-summary setup. There are some advantages to using this kind of a setup.
- It gives you a single place to apply changes that would normally be spread across multiple layouts
- The way the layout is displayed can be changed programmatically
- The layout elements in the sub-summary parts aren’t actually rendered until they’re shown
There are also some drawbacks:
- The layout is not search friendly
- i.e. sub-summary fields do not show in find mode so using it on layouts that the user needs to be able to search in can be difficult (but not impossible)
- The setup can become complicated very quickly.
- As you add more detail and layers of information into the layout, you have more factors you need to account for so that navigating through the different layout sort setups is fluid
- The layout can quickly become script heavy
- The more scripting necessary to drive your layout the more changes you have and landing in an unexpected arrangement
- The important thing is to keep your navigation scripts simple
All of that said, using a layout with sub-summary parts and no body part can give your solution a bit of extra flexibility. Sub Summary Without Body Part.fmp12