TextFields property

FormGroup.TextFields — { TextField }

The text fields of this form group as an array.

Accessing all text fields of a form group through this property has many uses:

The following sections detail how these scenarios can be realized. Skip to the examples at the bottom for the concise version.

Determining the length of the longest text field value

This formula returns the length of the longest value of a text field:

MAX(LEN(FormGroup1.TextFields))MAX(LEN(FormGroup1,TextFields))

The LEN function returns an array of the lengths of all the text field values, and MAX returns the largest such number.

The formula above can also be written as follows:

MAX(LEN(FormGroup1.TextFields.Value))MAX(LEN(FormGroup1,TextFields,Value))

However, as the LEN function is looking for an array of text strings, and text fields return text strings through their Value properties, .Value,Value is inferred and does not need to be spelled out.

In fact, you can make the formula even shorter:

MAX(LEN(FormGroup1))MAX(LEN(FormGroup1))

In the formula above, .Items.Value,Items,Value is inferred. In other words, the Items property is accessed, which includes not only fields, but also buttons and text boxes. As buttons and text boxes cannot return text strings, they are ignored by the LEN function, meaning that MAX(LEN(FormGroup1))MAX(LEN(FormGroup1)) returns the maximum length of all items that can return text strings, including text fields and text drop-down fields.

If you explicitly only want to include the values of text fields, and not values of text drop-down fields, be sure to write MAX(LEN(FormGroup1.TextFields))MAX(LEN(FormGroup1,TextFields)).

Determining the longest text field value

If you'd prefer to find not just the length of the longest text field value, but the actual value, use this formula:

LET(Fields := FormGroup1.TextFields, MaxCount := MAX(LEN(Fields)), LongestTextFields := FILTER(Fields, LEN(Fields) = MaxCount), INDEX(LongestTextFields, 1))LET(Fields := FormGroup1,TextFields; MaxCount := MAX(LEN(Fields)); LongestTextFields := FILTER(Fields; LEN(Fields) = MaxCount); INDEX(LongestTextFields; 1))

The formula above uses the LET function to assign names to intermediate values. First, the fields to process, FormGroup1.TextFieldsFormGroup1,TextFields, are assigned the name Fields. Then, the length of the longest text field value is found, using the familiar MAX(LEN(Fields))MAX(LEN(Fields)) formula fragment and assigned the name MaxCount.

The third step assigns the name LongestTextFields to an array containing all text fields whose values are maximally long. There may be multiple such text fields.

In order to build this array, the FILTER function is used. It accepts the fields as its first parameter and, as its second parameter, LEN(Fields) = MaxCountLEN(Fields) = MaxCount is given. The second parameter constructs a logical array, which is FALSE for all elements that correspond to text fields whose values are not equal to the calculated maximum length and TRUE for those that pass the test. In effect, FILTER returns an array containing only those text fields whose values are maximally long.

Finally, the INDEX function returns the first text field from the resulting array.

(It is also possible to use the REDUCE function to solve this problem in one step. Its documentation includes an example that does just that.)

If the text field that holds the longest value is part of FormGroup1, you'll get an error message. The reason is that a field cannot refer to itself, indirectly or directly, when calculating its value. To solve this issue, refer explicitly to the text fields that should be considered instead of using this property, and be sure to leave out the text field holding the result.

Enabling a button only if all text fields are valid

The Enabled property of a button determines if users can interact with the button. If a button should only be enabled if all text fields of FormGroup1 are considered valid, associate this formula with the Enabled property of the button:

AND(FormGroup1.TextFields.Valid)AND(FormGroup1,TextFields,Valid)

Above, the FormGroup1.TextFields.ValidFormGroup1,TextFields,Valid formula returns an array of logical values (TRUE or FALSE), where TRUE indicates that a text field is valid and FALSE indicates that a text field is invalid. The AND function, when applied to this array, returns TRUE only if all array elements are TRUE. In effect, the button is only enabled if all text fields of the form group are valid.

Making the background color red if a text field is invalid

The BackgroundColor property determines the background color of a screen and all screens that follow that have no explicit background color set. That means that if the background color is set for the first screen of an app, and no other screens have a background color set, the first screen determines the background color of the entire app.

We can make use of this knowledge to make the background of the entire app red, but only if at least one text field of the form group FormGroup1 is invalid. This formula is associated with the BackgroundColor property of the first screen:

IF(OR(NOT(FormGroup1.TextFields.Valid)), Color.Red)IF(OR(NOT(FormGroup1,TextFields,Valid)); Color,Red)

The formula fragment FormGroup1.TextFields.ValidFormGroup1,TextFields,Valid returns a logical array, where TRUE indicates that the corresponding text field is valid and FALSE indicates that the corresponding text field is invalid. Applying the NOT function to this array negates every element, meaning that TRUE indicates that a text field is invalid and FALSE indicates that a text field is valid. (The ! operator would have had the same effect.)

Then, the OR function is applied to this array. It returns FALSE only if all elements of the array are FALSE. In other words, it returns TRUE if one or several elements are TRUE, meaning that it returns TRUE if one or several text fields are invalid.

Finally, the IF function is used to return the color red if one or several text fields are invalid. Otherwise, IF returns a blank value, which has no effect on the background color. The net effect is that the background color of the app is made red if one or several text fields of FormGroup1 are invalid.

Including all text field values of a form group in an email

The Body property of email report buttons allows the body of an email to be set through a formula. While email report buttons have built-in support for including field values, through the IncludedFields property, building a text string manually to include in the email body allows us more flexibility.

Consider this formula, which should be associated with the Body property of an email report button:

TEXTJOIN(NEWLINE(), FALSE, FormGroup1.TextFields.Label & ": " & FormGroup1.TextFields.Value)TEXTJOIN(NEWLINE(); FALSE; FormGroup1,TextFields,Label & ": " & FormGroup1,TextFields,Value)

Above, the formula fragment FormGroup1.TextFields.LabelFormGroup1,TextFields,Label returns a text array, made up of the labels of the text fields of FormGroup1. The formula fragment FormGroup1.TextFields.ValueFormGroup1,TextFields,Value also returns an array, this time made up of the values of the text fields. Using &, the labels are joined together with the values, separated by a colon.

The resulting text array, where every element consists of a label, followed by a colon and a value, is converted into a single text string using the TEXTJOIN function. Its first parameter, NEWLINE()NEWLINE(), ensures that the array elements are separated from one another using line breaks.

Requiring all text fields of a form group to be filled out

The NextScreenAvailable property of form screens determines if users are allowed to move forward to the next screen. If a user should only be allowed to move forward once all text fields of a form group have been filled out, associate this formula with the NextScreenAvailable property of the screen that the form group is part of:

AND(ISDEFINED(FormGroup1.TextFields))AND(ISDEFINED(FormGroup1,TextFields))

The ISDEFINED function returns a logical array when its sole parameter is an array. TRUE elements in the array indicate that the corresponding text fields have defined values, that is, have been filled out, and FALSE elements indicate that the corresponding text fields have not been filled out.

Finally, the AND function returns TRUE only if all elements of the array are TRUE, otherwise it returns FALSE. The net effect is that AND returns TRUE only if all text fields of FormGroup1 have been filled out, prompting the NextScreenAvailable property to only allow users to proceed once all text fields have defined values.

Ranges versus this property

If the form group FormGroup1 only consists of the text fields Field1, Field2 and Field3, these formulas are equivalent:

FormGroup1.TextFieldsFormGroup1,TextFields
Field1:Field3Field1:Field3
{ Field1, Field2, Field3 }{ Field1; Field2; Field3 }

The second formula uses a range to create an array consisting of Field1, Field3 and all items that appear between them, which in this case is only Field2.

The chief advantage of the TextFields property, compared to a range, is that there is no need to update formulas when additional text fields are added to a form group. If Field4 were to be added to the form group, the Field1:Field3Field1:Field3 range would have to be changed to Field1:Field4Field1:Field4 everywhere it is used.

By contrast, FormGroup1.TextFieldsFormGroup1,TextFields automatically includes Field4, and any other text fields that are added.

Filtering text fields

If you want to process only a subset of the text fields returned from this property, use the FILTER function. It can base its decision on which text fields to return on the property values of the text fields.

This formula only returns visible text fields:

FILTER(FormGroup1.TextFields, FormGroup1.TextFields.Visible)FILTER(FormGroup1,TextFields; FormGroup1,TextFields,Visible)

Crucially, you can also filter on the names of the text fields, using standard text functions. This formula only returns text fields whose names include the text string "Required":

FILTER(FormGroup1.TextFields, CONTAINS(FormGroup1.TextFields.Name, "Required"))FILTER(FormGroup1,TextFields; CONTAINS(FormGroup1,TextFields,Name; "Required"))

If you use a deliberate naming strategy for your text fields, you can use FILTER in conjunction with this property to ensure that you only process a specific subset of text fields.

Related properties

Use the TextFields property of a screen to access all text fields of said screen and the TextFields property of the app object to access all text fields of the entire app.

The Fields property returns all fields of a form group, not just text fields. The Items property returns all items of a form group, including fields, buttons, text boxes and named values. Use NumberFields, SwitchFields, DateTimeFields, NumberDropDownFields and TextDropDownFields to access other kinds of fields.

Examples

MAX(LEN(FormGroup1.TextFields))MAX(LEN(FormGroup1,TextFields))

Returns the length of the longest value of a text field that belongs to FormGroup1. Refer to the main text for a formula that returns the longest value, and not just its length.

MAX(LEN(FormGroup1.TextFields.Value))MAX(LEN(FormGroup1,TextFields,Value))

Returns the length of the longest value of a text field that belongs to FormGroup1. If .Value,Value is left out, it is inferred.

AND(FormGroup1.TextFields.Valid)AND(FormGroup1,TextFields,Valid)

Returns TRUE if all text fields of FormGroup1 are valid and FALSE otherwise. FormGroup1.TextFields.ValidFormGroup1,TextFields,Valid returns a logical array, where each element reflects whether its corresponding text field is valid. Finally, the AND function returns TRUE if all elements are TRUE and FALSE otherwise.

TEXTJOIN(NEWLINE(), FALSE, FormGroup1.TextFields.Value)TEXTJOIN(NEWLINE(); FALSE; FormGroup1,TextFields,Value)

Returns all text field values of a form group as a text string, where values are separated from one another using line breaks. The formula fragment FormGroup1.TextFields.ValueFormGroup1,TextFields,Value returns an array of values, which the TEXTJOIN function joins together with line breaks.

AND(ISDEFINED(FormGroup1.TextFields))AND(ISDEFINED(FormGroup1,TextFields))

Returns TRUE if all text fields of FormGroup1 have been filled out. When the ISDEFINED function is applied to an array of text fields, it returns a logical array whose elements indicate if the corresponding text field has a defined value. The AND function returns TRUE if all array elements are TRUE and FALSE otherwise.