August 15th, 2010

A portal is a window to a related table. When you create a portal, you define the related table and the number of rows to be shown. Besides some other options you can also decide, whether the portal shall have a vertical scroll bar. Unfortunately FileMaker does not offer a direct way to change this option during run-time.

The size of the portal – and therefore the number of rows – may change at run-time. This will happen when you set vertical autosize option for the portal. Changing the height of the layout window will also change the size of the portal. There is no FileMaker function to get the number of actual visible portal rows. Even with such a function, you can not turn off the scroll bar when fewer records are shown in the portal.

To overcome this problem, I wrote two custom functions. These functions and a invisible object create an effect that will hide the portal scroll bar when fewer records than available portal rows are shown.

CF portal.rowCount

My first custom function will calculate the number of visible portal rows. It is inspired by a discussion in the German FileMaker Magazin forum and the custom function VisiblePortalRows from Fabrice Nordmann. He himself was inspired by an idea from Agnès Barouh and a solution by Alexandre Vialuses. So my thanks goes to these two developers as well.

Fabrice uses recursion to return a list with portal row values. For my project I am only interested in the number of visible portal rows (not the content). I came up with a solution that does not requires recursion.

Requirements

The function is called with a single parameter, the object name of the portal. Besides the portal, at least one other object inside the portal requires an object name. This can be any type of object, not necessary a table field.

Function portal.rowCount( _key; _params )
Let( [
	_objects = GetLayoutObjectAttribute( _name;  "containedObjects" );
	_objects = Substitute( "¨" & _objects & "¨"; ["< "; ""]; [">"; ""]; [¶; "¶¨"]; ["¨¶"; ""]; ["¶¨"; ¶]; ["¶¨"; ""]; ["¨"; ""] );
	_object = GetValue( _objects; 1 );
	_portal.height = GetLayoutObjectAttribute( _name;  "bottom" ) - GetLayoutObjectAttribute( _name;  "top" );
	_row.height = GetLayoutObjectAttribute( _object;  "top"; ""; 2 ) - GetLayoutObjectAttribute( _object;  "top"; ""; 1 )
];
	Round( _portal.height / _row.height; 0 )
)

Some explainations about the function code:

  • First, a list with all object names within the portal is evaluated.
  • In this list, all “< " and ">” and empty lines are removed.
  • The first element from this list is used as the object name inside the portal.
  • Now the actual height of the portal and the height of a single portal row is calculated. The latter is the distance between the same object in two consecutive portal rows.
  • The final calculation is just simple math: How often does the portal row fit into the portal height.

CF portal.recordCount

The next custom function is not really a necessity. It calculates the total numbers of records in a portal, including the invisible rows. This correlates with the number of related records in the portal table. This could be easily determined with the calculation Count( portalTable::someField ). But for this custom function you need only the object name of the portal. The name of the portal table and the name of a related field are automatically calculated.

Requirements

The function also expects a single parameter, again the object name of the portal. No other object names are required, but the portal should include at least one field from the related table.

Function portal.recordCount( _key; _params )
Let( [
	_to = GetLayoutObjectAttribute( _name;  "source" );
	_fields = FieldNames( Get( FileName ); Get( LayoutName ) );
	_line = PatternCount( Left( _fields; Position( _fields; _to & "::"; 1; 1 ) ); ¶ ) + 1
];
	Evaluate( "Count(" & GetValue( _fields; _line ) & ")" )
)

Some explainations about the function code:

  • The first step calculates the name of the table the portal is based on.
  • Then a list with all fields in the current layout is created.
  • In the next step the first line with a field from the related table is calculated.
  • With the name of the related table and a field from that table the count function is evaluated.

Notice

FileMaker 11 has a new feature: portal filtering. The above function portal.recordCount does not factor this in. It will calculate to number of related records before FileMaker applies the portal filter.

Hiding the Scroll Bar

With these two custom functions and a invisible text object, I can dynamically hide the portal scroll bar. The text object is a text with a single space. It is as wide as the portal scroll bar (on my Mac 13px) and at least one pixel taller than the portal. Both object are aligned with their right and bottom side. The text object is on top of the portal.

With this arrangement, the text object starts at least one pixel above the portal object. If both object were aligned with the top side, FileMaker would treat the text object as an object in the portal row. Both objects should have the identical autosize setting. The text object has no fill and no line color. But a conditional format is defined:
Condition: portal.rowCount( "portalName" ) >= portal.recordCount( "portalName" )
Format: Fill color white (or the corresponding background color of the layout)

Example

The following example shows the result. The portal has 10 rows. California has more than 300 related customers. Here is the scroll bar visible. But for example, Alaska has fewer customers. All six related records fit easily into the 10 portal rows. The scroll bar is therefore hidden.

2 Responses

This is very nice. I usually dislike workarounds, saying to myself something like “let it be ugly, but straightforward”, but this one is pretty.

[...] This post was mentioned on Twitter by dateimacher, FileMaker Newswire. FileMaker Newswire said: Dynamic Portal Scroll Bar http://bit.ly/dykYBp [...]

You must be logged in to post a comment.