View this page in the latest version of Appian. a!forEach() Function Share Share via LinkedIn Reddit Email Copy Link Print On This Page How to Use a!forEach() to Display a Dynamic List of Interface Components Watch this video to learn how to use the looping function a!forEach() in your interfaces to dynamically display components from a changing list of items. Evaluates an expression for each item in a list and returns a new array of the results. Related information: Arrays in Expressions: The a!forEach() function iterates over an array and can return a two-dimensional array, understanding array behavior helps you predict what a!forEach() returns. Looping Recipes: Browse ready-made interface recipes that use looping functions like a!forEach() to display dynamic lists of components, so you can adapt a working example instead of building an interface from scratch. Parameters a!forEach( items, expression ) Keyword Type Description items Any Type Array Array or DataSubset containing the items over which to iterate. expression Any Type The expression to be evaluated with each iteration. The following function variables are available in this parameter: fv!item (the current array item) fv!index (the current item's index in the array) fv!itemCount (the number of items) fv!identifier (when using a DataSubset, the current item's identifier) fv!isFirst (true during the first iteration, false afterward) fv!isLast (true during the last iteration, false beforehand) Returns Any Type Array Using the function The following sections cover important details about the a!forEach() function. When to use the function Use a!forEach() when you need to perform the same expression for each item in a list and get back a list of results. For example, you could use a!forEach() to: Display the same component for each item in a list, like rows in an editable grid, repeating sections, or a list of buttons. Generating a list of user filter options. Building dynamic interface elements like tab buttons. Concatenating two fields in a CDT for each item in a list, like concatenating first name and last name to show the full name of an employee. Using the items parameter The items parameter of a!forEach() accepts an array, a DataSubset, a two-dimensional array, or a single value. The following sections describe how a!forEach() handles each case. Null or empty items list When items is null or an empty list, a!forEach() returns an empty list of the same type as items and does not evaluate the expression. For example, a!forEach(items: null, expression: length(fv!item)) returns {}. DataSubset as the items value When items is passed a DataSubset, a!forEach() iterates through the DataSubset's data field. If the DataSubset's identifiers are populated, the following requirements apply: Uniqueness and length: The identifiers must be an array of unique items and must be the same length as the data field. Interface behavior: In an interface, a!forEach() uses the identifiers to associate local variables with particular rows. For example, a!forEach(items: a!dataSubset(data: {1, 2, 3 }), expression: fv!item + 2) returns {3, 4, 5}. Two-dimensional array as the items value If a two-dimensional array is passed to the items parameter, a!forEach() evaluates the expression once for each item in the outer array. In these cases fv!item may be an array. For example, a!forEach(items: merge({1,2}, {10,20}), expression: fv!item[1] + fv!item[2]) returns {11, 22}. Single value as the items value If you pass a single value to the items parameter instead of an array, a!forEach() treats it as a list with one item. a!forEach() evaluates the expression once for that value and returns a single-item list. Null values and DataSubsets are handled differently, as described in the Null or empty items list and DataSubset as the items value sections. For example, a!forEach(items: 3, expression: fv!item + 1) returns {4}. Runtime type of fv!item When iterating over items, a!forEach() always casts fv!item to its runtime type, so fv!item will not appear to be Any Type even if that is what was passed in to items. For example, a!forEach(items: {1, "hello"}, expression: typename(typeof(fv!item))) returns {"Number (Integer)", "Text"}. Using the expression parameter The expression parameter of a!forEach() defines what to evaluate for each item. The following sections describe what the expression parameter accepts, how a!forEach() evaluates it, and what it returns. Supported values in the expression parameter The expression parameter of a!forEach() accepts any valid expression, including rules, functions, and constants. a!forEach() evaluates the expression once for each item and appends each result to the returned list in the same order as the corresponding item in items. For example, a!forEach(items: {1, null, 3}, expression: if(isnull(fv!item), "No Value", "Value: " & fv!item)) returns {"Value: 1", "No Value", "Value: 3"}. For example, a!forEach(items: {100, 200, 300}, expression: fv!item + 1) returns {101, 201, 301}. Function variables The following function variables are available when configuring the expression parameter of a!forEach(): fv!item (Any Type): The current item. fv!index (Integer): The current item's index in the items array. fv!identifier (Any Type Array): When items is a DataSubset with identifiers, the current item's identifier, otherwise null. fv!isFirst (Boolean): True for the first item in the items array, otherwise false. fv!isLast (Boolean): True for the last item in the items array, otherwise false. fv!itemCount (Integer): The total number of items (including nulls). Parallel evaluation of queries When the expression parameter contains a query, a!forEach() can evaluate its iterations in parallel to reduce the overall evaluation time. This happens automatically and does not change the result. For details on how Appian evaluates queries in parallel, see Parallel Evaluation of Expressions. Array results If the result of any expression is an array, a!forEach() returns a two-dimensional array. Two-dimensional arrays can be useful when processing data, but not all functions support them. Two-dimensional arrays are auto-flattened into one-dimensional arrays upon being stored in a process variable, node input, typed rule input, or custom data type field. Local variables, however, can store the two-dimensional array without flattening. For example, a!forEach(items: {1, 2, 3}, expression: enumerate(fv!item)) returns a three-item list consisting of {0}, {0, 1}, and {0, 1, 2}. You can use a!flatten() on the result of a!forEach() to convert it to a one-dimensional array. Examples The following examples demonstrate the a!forEach() function. To experiment with examples, copy and paste the expression into an expression rule and click TEST RULE to see the output. Use the same variable multiple times This example uses a!forEach() with the fv!isFirst and fv!isLast function variables to format a list of words into a single sentence. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 concat( a!forEach( items: {"the", "variables", "fv!isFirst", "and", "fv!isLast", "are", "helpful"}, expression: concat( if( fv!isFirst, proper(fv!item), fv!item ), if( fv!isLast, "!", " " ) ) ) ) Returns "The variables fv!isFirst and fv!isLast are helpful!" Using multiple function variables This example uses a!forEach() with the fv!index and fv!item function variables to report each word's position and length. 1 2 3 4 a!forEach( items: {"apple", "pear", "banana"}, expression: "Word " & fv!index & " is length: " & len(fv!item) ) Returns {"Word 1 is length: 5", "Word 2 is length: 4", "Word 3 is length: 6"} Using a!forEach with interface components In the interface, the expression parameter can contain interface components, a!localVariables() variables, and load() variables. To edit the current array item, interface components must save values into fv!item instead of indexing back into the original array so that a!forEach() can keep local variables associated with the correct rows. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 a!localVariables( local!names: {"Alice", "Bob", "Carol"}, a!forEach( items: local!names, expression: a!localVariables( local!modified, a!textField( instructions: if(local!modified, "Modified!", ""), value: fv!item, saveInto: { fv!item, a!save(local!modified, true) } ) ) ) ) If the original array needs to be modified without writing to fv!item, either because it is being changed outside the a!forEach() loop or because a loop iteration is modifying an item besides the current one, then use a DataSubset with identifiers to make sure local variables are associated with the correct rows. Using a!forEach with record data in interface components This example references record types from another environment and will error if you try to use it in yours. Use it as a reference only. Using a!forEach(), you can create a list of record field values without knowing the size of the final list. In this example, we'll query the Department record type with a!queryRecordType() and then store the result in a local variable. Use a!forEach() to iterate over the list of departments and build a list from the value field of each record. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 a!localVariables( local!records: a!queryRecordType( recordType: recordType!AT Department, fields: recordType!AT Department.fields.value, pagingInfo: a!pagingInfo( startIndex: 1, batchSize: 10, sort: a!sortInfo( field: recordType!AT Department.fields.value, ascending: true() ) ), ).data, { a!richTextDisplayField( labelPosition: "COLLAPSED", value: { a!richTextItem( text: a!forEach( items: local!records, expression: if( condition: fv!isLast, valueIfTrue: "and " & fv!item[recordType!AT Department.fields.value] & ".", valueIfFalse: fv!item[recordType!AT Department.fields.value] & ", " ) ) ), } ) } ) The resulting interface will look similar to this example: Nesting a!forEach If you need to nest an a!forEach() inside another a!forEach() and want to refer to the outer fv!item, you can either put it in a local variable before calling the second a!forEach() or put the inner call in a separate rule and pass in fv!item via a rule input. For example: 1 2 3 4 5 6 7 8 9 10 a!forEach( items: {"January", "February", "March"}, expression: a!localVariables( local!month: fv!item, a!forEach( items: {1, 15}, expression: local!month & " " & fv!item ) ) ) Returns a three item list containing {"January 1", "January 15"}, {"February 1", "February 15"}, and {"March 1", "March 15"} Feature compatibility The table below lists this function's compatibility with various features in Appian. Feature Compatibility Note Portals Compatible Offline Interfaces Compatible Sync-Time Custom Record Fields Compatible Can be used to create a custom record field that only evaluates at sync time. Real-Time Custom Record Fields Incompatible Custom record fields that evaluate in real time must be configured using one or more Custom Field functions. Process Reports Incompatible Cannot be used to configure a process report. Process Events Partially compatible If autoscale is enabled, can be used to configure a supported process event node (such as a start event or timer event). Process Autoscaling Compatible Can be used in autoscaled processes. Event Consumer Filter Conditions Compatible Can be used in filter conditions. Event Consumer Event Handlers Compatible Can be used in event handler expressions. Feedback Was this page helpful? SHARE FEEDBACK Loading...