By Daniel Wood, 22 August 2011
Displaying a long list of items on a layout generally means that the majority of the list is hidden from the user until they click into the field, with no feedback as to the size of the list. This article details a nice technique you can use to present the same list in a truncated style that gives live feedback on the number of items.
Consider the field shown below containing a return-delimited list of values:
Here we have a list but the size of that list is unknown. For all we know it could contain just the twelve names shown, or it may contain far more. The only way at this stage to get an idea of the size of the list is to click into it and then scroll through the names. Doing this however will still not give you a very good indication of the number of items in the list.
One way to overcome this issue would be to give the user some kind of visual cue as to the size of the list. This would not only alert them to the fact that there are more items in the field than currently shown, but it also also tells them how many items there are.
This could be achieved in various ways, one of which serves as the basis of this article and which we think is rather cool.
For lack of a better name, this technique has been denoted +More due to the display it gives. Below is a picture of what we are ultimately going to end up with.
The last displayed line in the field now tells us how many more items there are in the list. In this case the size of the list is the 11 displayed items plus 66 more, giving a total list size of 77 items.
The effect is achieved by overlaying another object on top of the entry field. When the user clicks onto it, they are in fact clicking into the field underneath, and so can begin to edit the field contents.
We have in fact placed a calculation field over the regular field, as shown below.
The calc field has been filled with white colour so as to completely obscure the underlying field.
One thing a user may end up doing on the layout is anchoring the field so that when the window is resized, the height of the field changes. Generally for lists this means more or less items are displayed when resized. The implications for our technique are that we need the display to dynamically update when the window is resized, so that the number of values shown, and the number of other items displayed is always accurate. All of this is taken care of using a special custom function we created to produce the display.
The following single line of code is specified in the calculation:
truncateList ( Home::Values ; 18 ; "MainList" )
The custom function accepts three parameters:
Let ( [
totalValues = ValueCount ( theList ) ;
objectHeight = GetLayoutObjectAttribute ( objectName ; "Height" ) ;
numLines = Floor ( objectHeight / lineHeight) ;
visibleLines = numLines - 1
totalValues â¤ numLines ;
LeftValues ( theList ; visibleLines ) &
TextStyleAdd ( TextColor ( "(+ " & totalValues - visibleLines & " more)" ; RGB ( 62 ; 108 ; 176 ) ) ; Bold )
So what is the function doing? Well, the first thing it does is determine the total number of items in the list so we know how many to display and how many remaining we need to show.
Next, it uses the GetLayoutObjectAttribute function to determine the current height of the displayed field on the layout. The reason for this is that anchoring and layout resizing can affect the size of the field at any given point in time, which will in turn affect what we display.
With that information known, we can now determine the number of lines of text that the field is capable of fully displaying currently. This is a simple calculation of dividing the fields height by the height of a single line.
We also determine how many actual values the field can display if our +More line is used. This is always one less than the total number of lines the field can display.
We now have everything we need to formulate the display. If the field is capable of showing the entire contents of the list then we simply show the list. If however it cannot, then we are going to show part of the list with our +more line as the last line. This part of the function also adds some colour and style formatting to the last line.
So that's it, pretty simple really, nothing too over the top.
The end result of the custom function and display calculation is a nice and simple to implement way to display a list of values to the users.
As the layout is resized, the calculation is re-evaluated and the display updated. The changes to the display are instant when the window is manually resized which is nice, as illustrated in this crude animation below:
The technique we have shown makes use of an additional calculation field for the purposes of the display. What this means is that a new calculation field is required in conjunction with the actual list field. A bit of a hassle really, but there are some reasons why we ended up taking this approach.
The following part of the article details our initial thinking of implementing this technique, and why it failed causing us to revert to a calculation field. Hopefully this proves useful and you may get some cool ideas out of it - for this particular technique however it was not good enough (you can stop reading now if you just wanted the above technique!)
When first tackling it, we looked for a technique that didn't require any additional fields in the schema. What we came up with was using merge variables to achieve this.
So we defined a merge variable called $$ListDisplay and overlaid it on the field. The next trick was to have the variable define itself. We wanted the display to change whenever the user resizes the window, so we decided to make use of the layout objects conditional formatting as a means to define the variable. Conditional formatting re-evaluates during a screen redraw, so we thought this was perfect!
On the merge variables conditional formatting we defined the following:
Basically it is the calculation definition but instead we are setting the global variable to it instead by using a Let statement within the conditional formatting.
When we jumped into browse mode and began resizing the layout window by dragging it larger, we noticed that it appeared to work perfect! The merge variable was refreshing live as we resized the window and everything was good with the world.
Fast forward a few seconds however and the world began to crumble before our eyes.
It turns out merge variables don't like to play ball when it comes to screen redraws, and their behavior in that department is quite erratic. Certain actions did not force the merge variable to refresh:
The first two were killers, as to get it to work properly meant workarounds such as script triggers to force a refresh. In fact, it is worse than that as a simple refresh window step wasn't even enough, we had to introduce a brief 0.1 second pause prior to any screen refresh, no thank you!
The last one was peculiar too. Turns out the merge variable evaluated before the conditional formatting did, thus the initial view was an empty global variable and so no display. Only after the first screen redraw did the variable get initialized. This could have been remedied by setting it in the startup script but that still isn't very nice.
The moral is what might look great at first has to be tested to the point where it no longer looks so good :) It was a good thought but too many issues.
Please find attached an example file. This file was used for all the screenshots in this article, and is provided to help you fully understand what is going on in this article, and to let you experiment in FileMaker with this solution.