Multiselect List or Portal

 

This function is already quite old and has been solved many times. You can find all kinds of approaches, and there are plenty of existing functions available on the internet.
Nevertheless, I would like to show a simple solution using a custom function that works both for record lists and portals.

First, let’s clarify what the function is supposed to deliver.
Most of the time, such a function is used to collect a set of IDs that then serves as a multi-key for subsequent tasks.

So we need a function that reads the contents of any field and collects those values into a list.
In our example, we simply store this list in a global variable called $$selectedItems.

In FileMaker, the command
GetField ( “TableName::FieldName” )
provides a very easy way to retrieve the contents of a field. Since the value is text, it is ideal to pass it as a script parameter.

Let’s start with the implementation for a record list.

For the script, we want to support the same keyboard and mouse behavior as in the operating system:

No key pressed: select a single record

Command key: add or remove the record from $$selectedItems (toggle selection)

Shift key: collect the field contents from a starting record up to the record that is clicked while holding Shift

So we create a script that evaluates the pressed modifier keys and behaves accordingly.

 

If [ Get(ActiveModifierKeys) = 2 or Get(ActiveModifierKeys) = 0 ]
# Handle No Mod Keys
Else If [ Get(ActiveModifierKeys) = 1 or Get(ActiveModifierKeys) = 3 ]
# Handle Shift
Else If [ If( Get(SystemPlatform) = - 2 ; //Windows - Check for ctrl and ctrl + caps
Get(ActiveModifierKeys) = 4 or Get(ActiveModifierKeys)= 6; //Mac / Other - Check for option and option + caps
Get(ActiveModifierKeys) = 16 or Get(ActiveModifierKeys) = 18 ) ]
# Handle Ctrl / Apple (Mac) Equiv
End If

Next, we build the script parameter as JSON.

JSONSetElement ( "" ; 
[ "tableNameFieldname" ; "Tablename::Fieldname" ; 1 ] ;
[ "nr" ; 10 ; 2 ]
)

Let’s extend the script by adding a script parameter.

Set Variable [ $sp ; Value: Get ( ScriptParameter ) ]
Set Variable [ $tablenameFieldname ; Value: JSONGetElement ( $sp ; "tableNameFieldname" ) ]
Set Variable [ $IDs ; Value: GetField ( $tablenameFieldname ) ]
Set Variable [ $nr ; Value: JSONGetElement ( $sp ; "nr" ) ]
If [ Get(ActiveModifierKeys) = 2 or Get(ActiveModifierKeys) = 0 ]
# Handle No Mod Keys
Else If [ Get(ActiveModifierKeys) = 1 or Get(ActiveModifierKeys) = 3 ]
# Handle Shift
Else If [ If( Get(SystemPlatform) = - 2 ; //Windows - Check for ctrl and ctrl + caps
Get(ActiveModifierKeys) = 4 or Get(ActiveModifierKeys)= 6; //Mac / Other - Check for option and option + caps
Get(ActiveModifierKeys) = 16 or Get(ActiveModifierKeys) = 18 ) ]
# Handle Ctrl / Apple (Mac) Equiv
End If

 

Before we complete the script, we create the custom function for collecting the field values:

MultiSelect ( field ; start ; end )

The function iterates upward through the records using WHILE and, if necessary, swaps start and end
when start > end.

While ( 
[
start = If ( start ≤ end ; start ; end ) ;
end = If ( start ≤ end ; end ; start ) ;
max = If ( start = end ; start ; end ) ;
out = "" ;
i = start
] ;

i ≤ max ;

[
out = List ( out ; GetNthRecord ( GetField ( field ) ; i ) ) ;
i = i + 1
] ;

out

)

In the complete script, we use the custom function in several places.

# Multiple Select [ Tablename::Fieldname ]

#
# Scriptparameter
# JSONSetElement ( "" ;
[ "tableNameFieldname" ; "Tablename::Fieldname" ; 1 ] ;
[ "nr" ; 10 ; 2 ]
)
# nr = if portal : Get ( ActivePortalRowNumber )
# nr = if record list : Get( RecordNumber )
#
Set Variable [ $sp ; Value: Get ( ScriptParameter ) ]
Set Variable [ $tablenameFieldname ; Value: JSONGetElement ( $sp ; "tableNameFieldname" ) ]
Set Variable [ $IDs ; Value: GetField ( $tablenameFieldname ) ]
Set Variable [ $nr ; Value: JSONGetElement ( $sp ; "nr" ) ]
If [ Get(ActiveModifierKeys) = 2 or Get(ActiveModifierKeys) = 0 ]
# Handle No Mod Keys
Set Variable [ $$selectedItems ; Value: GetField ( $tablenameFieldname ) ]
Else If [ Get(ActiveModifierKeys) = 1 or Get(ActiveModifierKeys) = 3 ]
# Handle Shift
If [ $$lastRowNr <> "" ]
If [ $$lastRowNr > $nr ]
Set Variable [ $$selectedItems ; Value: MultiSelect ( $tablenameFieldname ; $nr ; $$lastRowNr ) ]
Else If [ $$lastRowNr < $nr ]
Set Variable [ $$selectedItems ; Value: MultiSelect ( $tablenameFieldname ; $$lastRowNr ; $nr ) ]
Else
# $$lastRowNr = $nr
Set Variable [ $$selectedItems ; Value: $IDs ]
End If
Else
Set Variable [ $$selectedItems ; Value: $IDs ]
End If
Else If [ If( Get(SystemPlatform) = - 2 ;
//Windows - Check for ctrl and ctrl + caps
Get(ActiveModifierKeys) = 4 or Get(ActiveModifierKeys)= 6;
//Mac / Other - Check for option and option + caps
Get(ActiveModifierKeys) = 16 or Get(ActiveModifierKeys) = 18
) ]
# Handle Ctrl / Apple (Mac) Equiv
Set Variable [ $$selectedItems ; Value: Let ( [ theList = $$selectedItems ;
searchElement = GetField ( $tablenameFieldname ) ] ;
If ( ValueCount ( FilterValues ( searchElement ; theList ) ) > 0 ; Substitute ( theList ; [ searchElement & ¶ ; "" ] ; 
[ searchElement ; "" ] ) ; List ( theL… ]
End If
Set Variable [ $$lastRowNr ; Value: $nr ]
Commit Records/Requests [ Skip data entry validation ; With dialog: Off ]
Refresh Window []

What’s really interesting here is only this line

# Handle Ctrl / Apple (Mac) Equiv
Set Variable [ $$selectedItems ; Value:
Let (
[
theList = $$selectedItems ;
searchElement = GetField ( $tablenameFieldname )
] ;
If ( ValueCount ( FilterValues ( searchElement ; theList ) ) > 0 ;
Substitute ( theList ; [ searchElement & ¶ ; "" ] ;
[ searchElement ; "" ] ) ;
List ( theList ; searchElement )
)
]

 

which performs an XOR operation:
if the field value is already in the list, it is replaced with “”; otherwise, it is appended to the list.

Now all that remains is to call the script using JSON as the script parameter.

For a record list:

JSONSetElement ( "" ; 
[ "tableNameFieldname" ; Get ( LayoutTableName ) & "::ID" ; 1 ] ;
[ "nr" ; Get ( RecordNumber ) ; 2 ]
)

or a portal:

JSONSetElement ( "" ; 
[ "tableNameFieldname" ; "Main~Sub#ID_Main::ID" ; 1 ] ;
[ "nr" ; Get ( ActivePortalRowNumber ) ; 2 ]
)

You have any questions? Feel free to send me an email, I’ll try to answer as soon as possible.