This post builds on the session I presented at DevCon 2015: Data Modeling Beyond Anchor Buoy which described the FileMaker Selector-Connector pattern for the relationship graph. At DevCon we also went through some sample files which are available here in the “DevCon 2015 Demo Files” section. We’ll reference those files in this article as well. (You can also think of this as a continuation of my the earlier post on Selector-Connector: “FileMaker Data Modeling with Selector Connector“.)
DevCon 2015 was an exciting time for the Selector-Connector Model as Todd Geist won the Excellence award for both developing and formalizing the idea. I was very fortunate to have the opportunity to collaborate with Todd as the idea was developing. This collaboration lead to the current model used in our SeedCode Complete template, and was the basis of my DevCon presentation.
Why A New Model?
On of the things I wanted to stress in my DevCon session is that there was never an intention to come up with something new in the abstract sense of a “model”. Todd and I both had a specific problem we wanted to solve: we wanted to build portable choosers (aka pickers and selectors), e.g. a chooser that we could easily move from layout to layout. Not only would this make our development go considerably faster, but in the case of SeedCode Complete, our customers would be able to take advantage of this portability as they customized and expanded the template.
As it turns out, there are other benefits to the Selector-Connector that emerged, but focussing on the chooser is arguably best way to understand Selector-Connector.
An Anchor Buoy Chooser
As I mentioned above, there was no intention to introduce a new data model or replace Anchor Buoy (and indeed, Selector-Connector doesn’t replace it). Anchor Buoy (AB) has served me well since the graph was introduced in FileMaker 7, and even if I was going to bend some of the AB rules, I would do so as little as possible. With this in mind, I started developing the newest version of SeedCode Complete using the AB model and intended to take it as far as I could. This also had some additional practical appeal as it could lead to a clear process for “retrofitting” an existing AB solution with any new benefits that emerged. What I started with very much resembled the demo file aABChooser.FMP12 (from “Selector-Connector Example Files” here); a basic file with Contacts, Projects and Invoices. Projects would allow for multiple project contacts, so I would build the chooser there first.
If we look at the graph for aABChooser.FMP12, we see that it is still following the AB model. The table occurrences (TOs) needed for the chooser have been added as buoys to the Projects anchor. If we wanted to maintain a strict Anchor Buoy model, then adding a chooser to Invoices would require adding duplicate versions of these TOs to Invoices as buoys. This is, in fact, the model that the previous version of SeedCode Complete followed, and although certainly better than starting each chooser from scratch, it still required a fair amount of additional development effort for each chooser. This was as far as we could take the AB model in our goal for a truly portable chooser.
A Universal Context Chooser
In the file bUCChooser.FMP12, we’ve moved our chooser TOs from being Project buoys to a new position at the top of the graph. We’ve created a new table called UC; this is for Universal Context which was the working term both Todd and I were using for “Selector-Connector” at the time. This new table would consist of one record and a few global fields for managing the chooser. All the anchors would now be related to this new table via an x-join relationship with globals on both sides. I knew I wanted to use globals, so I didn’t trip any downloading of indexes, and only the x-join relationship supports globals on both sides.
Happily, it’s very easy to make this change from aABChooser.FMP12 to bUCChooser.FMP12. Even though we broke the relationship between Projects and the ContactChooser TO, the script references to the TO itself do not change. When we reconnected ContactChooser to Projects via the UC table, all references to ContactChooser from the Projects context remained intact. Only the global fields that were moved from Projects to the UC table needed to be “re-referenced” in our scripts and calculations.
One of the benefits to this new model that was not planned, but soon became apparent, was that the global fields that now live in UC would have usually needed to live in the anchor tables in an AB model. By introducing the UC table, not only were we working towards a shared chooser, but we were also able to take a whole class of global utility fields out of the anchor tables and consolidate them in the new table.
We now had a working chooser for Projects that should be easy to use from any additional anchor layout; we would just need to add an x-join relationship from the new anchor to the UC TO. However, before we proceeded to hook up our other anchors we wanted to get our chooser fully functional. This meant not only being able to select an existing Contact, but to use the chooser to create a new Contact from within the chooser.
“Pop-Back” and The Selector
Adding the ability to create a new Contact from the chooser turned out to be remarkably easy, and this was really the point where I realized we were onto something cool.
As we all know, FileMaker allows the ability to create new records through a relationship. And any fields that are set up as match keys in the relationship force the newly created child record to inherit the values for these fields from the parent, thus making sure the relationship remains valid after the new record is created. However, less well known is what happens if the parent value for one of the match fields is empty. If the child field is set to auto-enter a value, then that value will be “popped back” to the parent record. Presumably this is FileMaker’s attempt to maintain the relationship after the creation of the child record. “Pop-Back” is the term I learned for this behavior. Our friend Kevin Frank refers to it as the “Magic Key” which I’ve also always liked.
For our creating new Contacts in our chooser, this behavior works perfectly. If we want to create a new record, we just need to add a new global field to the UC table and then add a creation relationship to Contacts with the global field and the Contact’s primary key (shown below). We then need to make sure our global is empty and expose the fields from this new relationship in our selector (editable fields like FirstName, LastName, etc.). As soon as the user types into these fields, the new record is created and the primary key value is popped back to the global.
Although there’s no editing involved with our chooser, it was clear that this relationship could also be used for editing an existing record from any context as well. Rather than clearing the global field, we’d set it to the primary key of an existing record we wanted to edit. This is where the language and term for the “Selector” started to take form, and Todd deserves the credit for clarifying the naming pattern. The central table with the global fields becomes the Selector. This name fits well because it’s the globals in this table occurrence that you manipulate to form a relationship with the “Selected” record. The table occurrences to the right become the Selected, i.e. SelectedContact. With this naming convention, the workflow becomes very clear:
- Set the global in the Selector to edit a specific record
- Clear the global in the Selector to create a new record
- The “Pop-Back” behavior means no additional steps are required for record creation
Applying these changes, we now have our file cSelector.FMP12 which allows us to search and add multiple Contacts to our Project records using the Selector Model. We should now be able to easily add our Contact chooser to Invoices simply by “hooking-up” our Invoice buoy to the Selector, but we have one more issue to solve first.
Finish In Context
Although we’ve gone a good ways to make our chooser universal, we still ultimately need to write our chosen record somewhere and in a specific context. Using indirection is one possibility. We could detect our context and then write to the appropriate key field, something like:
Set FieldBy Name [ Get(LayoutTableName) & “::id_Contact” ; $$sc_SelectedContactID ]
However, I’ve found these types of script steps somewhat fragile and difficult to support. We also have a different process in the case of Projects where we need to create a join record, so my single script step would invariably need some branching in addition to the indirection, and I think that’s too much complexity. For SeedCode Complete, I opted to use separate scripts for each context and then attach one of these unique scripts to the “save” buttons in that context’s chooser. This way, you could copy and paste the chooser from one context to another, and just change the save buttons. This is very much like what’s set up in the cSelector.FMP12 file. We have specific scripts for Saving the contact to both the Projects and the Invoices. All the other chooser scripts are universal.
There are other ways to do this final step of specifying where to write the newly chosen record:
Todd uses an interesting method where he adds an invisible button to the chooser and then in his chooser’s scripts he adds a step to go to this invisible button. The idea is to add the context specific script as an on-enter script trigger to this object. Todd calls these Virtual Script Triggers. This way, the scripts that work with the chooser never change, and you delegate the context specific logic to triggers. It doesn’t really save any lines of code, but it’s a very good way of separating the logic.
The Natural Hook
One of the things I accidentally stumbled across was some “natural” script-hook behavior. One of FileMaker’s behaviors is that when exiting a pop-over, the pop-over button always becomes selected. This behavior used to annoy me and I found myself always adding Go To Object steps, or changing the selected styling of the pop-over button so that you wouldn’t notice it. However, I realized that since I could count on it to act this way, the script trigger could be added to the pop-over button itself. I really like this because you don’t need to name the object with the hook attached to it. This means you don’t need the Go To Object step and (more importantly) you don’t have to worry about your object names breaking and morphing into something like “ChooserHook 2 Copy 3 Copy 2”. You can see the natural hook in action in the file dSelectorHook.FMP12.
FileMaker Select0r Connector: Does It Work?
Now that we’ve established our method for writing our chooser results back to context, there’s nothing left to do but the final steps to add the chooser to invoices. For the final file eSelectorFinal.FMP12, we just need to add our cross join relationship between Invoices and the Selector. We then copy and paste the pop-over button that encloses the chooser from Projects to Invoices and re-style it to fit the new layout. Lastly we add the new hook to the pop-over button as an on-enter trigger. The script we’re calling here is simpler than the one in Projects since we’re just writing back to the Invoice foreign key rather than creating a join record. Back to Browse…and it works! Our chooser is now highly portable and we’ve established a pattern for building new choosers for different entities.
I have deployed selector connector heavily in our solution but I am having a problem with gaining access to settings and other records through connector when there is no founds set. I only have this problem in instances where we are using RLA. The user and can the settings if there is a found set, a full access and see the settings if there is no found set, but an user with RLA cannot see the setting if there is no found set. the user has access to all the fields and tables required. This is putting a bit of a cramp on our programming. Has this problem come up with anyone else?
Here is Jason’s presentation on Selector-Connector at DevCon 2015: https://community.filemaker.com/videos/1698
I just watched your deacon 2015 selector-connector talk. Well done! I work from my home office and can’t afford to go to the DevCon’s so this was great as I was able to bring myself more up to date. I had done some rudimentary coding that was similar and your talk really solidified solving the issues I was having. Is there any way I could get the SCDemoFiles. The Devcon speaker link is only available to those who went to DevCon. Thanks again.
You can download them here: http://www.seedcode.com/downloads/ in the “DevCon 2015 Demo Files” section as SCDemoFiles.
I downloaded the sample files but they don’t run – I cannot see any of the functionality, although the scripts are all there. I am using FM 13 Pro Advanced – is this the problem?
Unfortunately, I made these for 14 and used some 14 only features, particularly the button bars. Other than those these techniques work fine in 13. If I get a chance I’ll add/update 13 compatible versions to the download.
Nice simple version of SelectorConnector! Where is the code that it is highlighting the search text on the list of found contacts. I am thinking it is in the style ‘chooser-display’. Is there some css that highlights any text that is equal to ContactSearchGlob field or something??
We’ve actually got that in the virtual list calc itself. ContactChooser::Display.
Thanks! nice and simple. Forgot to check in the most obvious place. 🙂
Aside from the button bars used in the demo files should this work in Filemaker 13 as well. I have been try to learn this technique by rebuilding in use a Filemaker 13 solution I have. I have been using the aABchoser file to get myself started. When I rebuild this the Contact Chooser table does not show all contacts. There are no records.
There shouldn’t be. but I’ve made this tough! By using the button bar for the pop-over, I’ve locked that one to 14! The limitation hadn’t occurred to me at the time as I was taking the opportunity to get familiar with new 14 stuff.
Check the data viewer to see if the $$sc_contactIDs variable is populated. If so, then the SQL is all working and it’s something with loading the portal rows. Make sure the ContactChooser table is populated. If you’re rebuilding, that step is not obvious.
Thank you for the demo file it is greatly appreciated. When I add a new contact from the picker it looks like it adds a row to the portal but doesn’t fill the contact info unless you leave the layout and return. Does it need to run a refresh window/portal step in the add contact script or is this something where you would have to refresh the cross join?
It looks like it’s part of the hook behavior as it updates in cSelector but not the d and e files.
Thanks! I think I had stopped demoing the new contact at this point and didn’t bother to clean these up. I did get that working correctly in d and e and updated the download.
They’re a bit different than c because of the way we’re doing the hook, but basically you want to make sure you get the “pop-back” from the new record before closing the pop-over, so I add a Go To Field (no field specified) step to the beginning of the Save New Contact script. We don’t get the pop-back until the field exit, so we want to force that to happen. We also want to add a commit step to the end of Save Selected Contact To Project/Invoice scripts.
Thanks for the article and sample files. Most of my use for such a picker is not to search the entire contact table, but to filter the list ( i.e. don’t show contacts already included, only the contacts for a certain company or of a certain occupation / title). I have a pdf showing my modifications to make this happen., don’t see a way to share here. Where would you inject into the process to filter the list? Just curious if there is an easier way.
In the sample files, we are using SQL to filter the list by name, so it would be easy to add additional filters to that SQL statement, i.e. companyID, etc.
We’ve also got it set to show all Contacts if no filters are specified, but you’d probably want to change this if you had a lot of Contacts, or if you were going to add some additional filters like by company.
I have found that SQL does not scale as well for large tables, so if you’re going to have a lot of Contacts, you’d probably want to get the list of IDs for the chooser a different way. In SeedCode Complete we have a Control file where we do FileMaker finds in the background and use ListOf on the IDs to get them into the global variable. I used SQL for these files to keep it simple and single file.
Thanks it does help.
Control File?? does this bleed over into another technology? or is it pure FM?
Could you elaborate, “without giving away the farm”??
Inquiring minds and all that,
The “control file” is another filemaker file and comes from the idea of doing MVC (Model View Control) in FileMaker. The idea, in this context, being that you can do finds in the control file, and since it’s a separate file, it stays hidden and you don’t get any of the odd behavior that you get with offscreen windows from the same file (flashing, window restore on MS Windows). I think these control files work great with the Selector Connector model choosers, particularly since we now have the ListOf summary option. It’s easy and fast to set up a FM search in the control file and have the script return the ListOf Ids for the chooser and this is how we have it set up in SeedCode Complete.
Here’s some articles on MVC in FileMaker you might want to check out for a deeper look: http://www.clevelandconsulting.com/category/mvc/
Thank you for your further explanations on Selector-Connector.
This article mentions a number of demo files that I cannot find under DevCon 2015 Demo Files on your download page. Have you not had the opportunity to post them?
They’re zipped up as one download as SCDemoFiles right below the DB2FM download. Hit me up at [email protected] if you’re still having trouble getting to them.