Simple Truncated Displaying of Long Lists (+more)

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.

The Issue

Consider the field shown below containing a return-delimited list of values:

truncatedlist 1

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.

The (+More) Display

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.

truncatedlist 2

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.

Unstored Calculation Field

We have in fact placed a calculation field over the regular field, as shown below.

truncatedlist 3

The calc field has been filled with white colour so as to completely obscure the underlying field.

The Issue of Anchoring and Field Resizing

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.

How Do We Define The Calculation?

The following single line of code is specified in the calculation:

truncateList ( Home::Values ; 18 ; "MainList" )

The custom function accepts three parameters:

 

  • theList: The actual list to display
  • lineHeight: The height in pixels of a single line of text in the underlying field being displayed
  • objectName: The layout object name of the underlying field being displayed
Let ( [
totalValues = ValueCount ( theList ) ;
objectHeight = GetLayoutObjectAttribute ( objectName ; "Height" ) ;
numLines = Floor ( objectHeight / lineHeight) ;
visibleLines = numLines - 1
];
If (
totalValues ≤ numLines ;
theList ;
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.

Putting it all Together...

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:

What happens to the display as the window is scaled.

Implications of using a Calculation Field

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!)

 


EXTRA: Looking for a Solution with no Additional Fields

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.

truncatedlist 4

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:

truncatedlist 5

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:

  • Changing window size using + control in top left corner of window
  • Actually editing the field contents (quite a critical one)
  • Upon layout first loading after file opened

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.

Example File

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.

Download Example File

Something to say? Post a comment...

Comments

  • Daniel Wood 17/11/2011 9:33am (8 years ago)

    Thanks for the comments everyone.

  • Daniel Yoshio Matsumura 17/11/2011 6:45am (8 years ago)

    Hi Daniel.

    Nice technique, thanks for share it with us.

  • Minh Ton 05/09/2011 5:04am (8 years ago)

    Oops! sorry Daniel for mis-spell your name.

  • Minh Ton 05/09/2011 5:01am (8 years ago)

    Hi Denial,

    I though for awhile before i decided to write this comments to say thank you very much for all your great articles about fmp.
    First, i am very new to fmp and i have learned so much from most of your cool techniques for tackling real world problems. Recently i designed a couple fmp databases for managing R&D scientific data at work, and i find all of your articles are very helpful, straightforward, and great sources for someone new like me to learn many differences way for solving the problem and quickly able to apply many cool techniques for getting many of my significant job done.

    I am truly appreciated for all your great worked and sharing many smart techniques for solving real world problems.

  • atuf 02/09/2011 2:13am (8 years ago)

    Hi Daniel,
    Thanks for sharing this nice concept.

  • Atuf 02/09/2011 2:07am (8 years ago)

    Hi Daniel,
    its a nice concept.
    Thanks for sharing such concept.

  • HOnza 01/09/2011 6:22pm (8 years ago)

    Very good advice. Easy to do and huge impact on user experience. The ideas you share are brilliand, Daniel.

    For consistency between Mac and Windows I suggest always setting line spacing manually to fixed numeber of pixels for fields and text objects displaying multiple lines of text. Then you know exactly how many lines of text will fit, regardless of platform.

    The only limitation of this is that FileMaker Go ignores the line spacing property. Hopefully it will support it in future.

  • Daniel Wood 28/08/2011 5:52pm (8 years ago)

    Hi Michael, you are right there appears to be an issue with the RSS, I'll make sure that gets fixed this week. Cheers Kevin for the comment, it's always annoying to me how there are such differences between mac and pc when it comes to fonts.

  • Kevin Frank 28/08/2011 8:38am (8 years ago)

    Thanks for another great, thought provoking article and demo, Daniel.

    Incidentally, if you use Tahoma and set vertical line spacing to .8 lines on both the fields, it works perfectly cross platform. Tahoma's vertical line spacing is identical on Mac and PC... I haven't done much research on the subject, but I get the impression that this is not true of most other fonts.

  • Michael 27/08/2011 3:30pm (8 years ago)

    Strange. I didn't get the last 3 posts in my feeds.
    Anyway, good read. Somethings new to know about Floor ().
    Didn't work nicely with Windows. Had to bump it up to 22.

  • Daniel Wood 26/08/2011 10:49pm (8 years ago)

    Hi Richard, thank you for the comment, very useful information! One of the reasons for passing line height as a parameter to the custom function is for just that fact - different fonts, sizes, styles, line spacings etc all contribute to differing number of lines visible, so the line height has to be determined on a field-by-field basis on the layout. Granted I should have tested on windows for the benefit of the example file :-)

  • Richard Dyce 26/08/2011 10:39pm (8 years ago)

    Daniel - slight problem on Windows XP - it doesn't seem to be calculating the line height correctly. It displays the (+xxx more) provided you shrink the font, but then you get empty lines at the bottom. Given the size on the layout, anything less than Arial 15pt works.

    It seems to be a function of the size of the font. For 18pt, you can fiddle it so it works as is by changing the numlines calc:

    <pre>numLines = Floor ( objectHeight / ( lineHeight + 4 ) ) ;</pre>

    4 is a magic number, which seems to avoid chopping the (+...) text.

  • Simon Clement 26/08/2011 8:54am (8 years ago)

    To resolve the line wrap issue you could monitor line length and truncate text and append with an ellipses.

  • Rob Westergaard 26/08/2011 2:02am (8 years ago)

    Nice technique! Specifying the line spacing of both fields in pixels rather than lines would probably address Jeff's problem.

    There's also an edge case where a value is wider than the field and "wraps" to the next line. Not sure how to trap for that without a lot more coding, though.

  • Matt Petrowsky 25/08/2011 8:16am (8 years ago)

    Another great technique Daniel! Thanks so much for sharing!

  • Daniel Wood 25/08/2011 7:21am (8 years ago)

    Hi Jeff, thanks for the comment. Yes you are correct that different platforms, fonts, line spacing, styles etc all have an effect on the line height. This is why line height is used as a parameter to the custom function because every situation will be different, and line height is dependent on all of the above factors. I probably should have done a platform check in the example file though so that it works nicely for windows users too, always forget about that platform! ;)

    Hi Lee, thank you for your kind words, I really appreciate them!

  • Lee Lukehart of SavvyData 25/08/2011 2:54am (8 years ago)

    Nice implementation, Daniel! I always appreciate another way to better inform the user. Sweet that it dynamically recalcs ? no speed hit when hosted, either. Also appreciate your backstory RE why a calc field vs global variable. Thanks for all the great FM info you're sharing ? you're a real asset to the community, Sir!

  • Jeff 25/08/2011 2:42am (8 years ago)

    This is nice but it needs to be adjusted for font spacing on Windows. I don't know what the exact conversion should be but I added 22% to the line height and that seems to work.

    I really like this - Thanks!

RSS feed for comments on this page | RSS feed for all comments