---
schema_version: "1"
id: ef921379ebd2835c3b74508bb4ab6eaf38c2eb627c511a6b44b705ee13eac496
title: Use Array Functions for Multi-Select Widgets and Looping
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/analytics/atf/guides/atf-array-multi-select-looping.md
canonical_url: https://developer.salesforce.com/docs/analytics/app-template-framework/guide/atf-array-multi-select-looping.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: d9cfd07ce4ff626395f00fb9a762d6ef83d131a5914cb0bfdfe0199d128b9a68
products:
  - App Template Framework
  - analytics
---
# Use Array Functions for Multi-Select Widgets and Looping

Here’s how to use an array function to create a configuration wizard widget that lets the user select multiple values.

## Create a Multi-Select Widget

This `ArrayType` variable creates a wizard widget that lets the user select multiple values.

```json
"Account_Fields": {
       "label": "Pick the fields for your dataset",
       "description": "Multiselect sobjectfield test",
       "defaultValue": [
         {
           "sobjectName": "Account",
           "fieldName": "Name"
         }
       ],
       "required": false,
       "variableType": {
           "type": "ArrayType",
           "itemsType": {
               "type": "SobjectFieldType"
           }
       },
       "excludeSelected": true
   }
```

Results in the following wizard widget:

![This diagram depicts the resulting wizard question.](https://developer.salesforce.com/docs/media/atf/atf_multiselect_sobjectfield.png)

The `ArrayType` variable contains an `itemsType` attribute, which accepts the following:

- `SObjectType`
- `SObjectFieldType`
- `DatasetType`
- `DatasetDateType`
- `DatasetDimensionType`
- `DatasetMeasureType`
- `StringType`
- `NumberType`

## How the Widget Stores Selections

The widget places values in an array. The following show how the widget displays values for the user to select:

![These two images depict how selections in the widget are placed into an array.](https://developer.salesforce.com/docs/media/atf/atf_widget_array1.png)

![These two images depict how selections in the widget are placed into an array.](https://developer.salesforce.com/docs/media/atf/atf_widget_array2.png)

## Reference Array Items by Index

Items in the array can be referenced by index. Arrays of `StringType` and `NumberType` are easy to work with, but arrays of `SObjectType` and `SObjectFieldType` contain multiple attributes for each item in the array.

Array of `SobjectFieldType`:

| Expression                                  | Returns                                                                                      |
| ------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `${Variables.Account_Fields[0]}`            | (`sobjectName`=Account, `fieldName`=Name, `sobjectLabel`=Account, `fieldLabel`=Account Name) |
| `${Variables.Account_Fields[0].fieldName}`  | Name                                                                                         |
| `${Variables.Account_Fields[0].fieldLabel}` | Account Name                                                                                 |

**note:** `fieldName` is required for workflows.

## Access Array Values in Template Files

The selection values from the widget are stored in the variable. There are two ways to access them in the template files (rules, dashboards, workflow).

**Without looping**

Use array values from `SobjectFieldType` by index.

```json
"fields":[
  {"name":"${Variables.Account_Fields[0].fieldName}"},
  {"name":"${Variables.Account_Fields[1].fieldName}"},
  {"name":"${Variables.Account_Fields[2].fieldName}"},
  {"name":"${Variables.Account_Fields[3].fieldName}"},
  {"name":"${Variables.Account_Fields[4].fieldName}"}
]
```

This example, without looping, would be tricky to use, because there would always need to be at least five items in the array. Any fewer would fail, and anything over five would not be used.

**With looping**

Use array values from `SobjectFieldType` with the `array:forEach` function. In this example, a `“set”` action loops through the `SObjectFieldTypes` in the array and adds them to the `“fields”` attribute in the `Extract_Account` step of the workflow. Each entry in `“fields”` needs “name” and `“var.fieldName”`.

**rules.json**

```json
"name": "AddAccountFilesToWorkflow",
  "appliesTo": [
    {
      "type": "workflow",
      "name": "*"
    }
  ],
  "actions": [
    {
      "action": "set",
      "description": "use selected values for sfdcDigest in workflow",
      "path": "$.workflowDefinition.Extract_Account.parameters.fields",
      "value": "${array:forEach(Variables.Account_Fields, '{\"name\": \"${var.fieldName}\"}')}"
    }
  ]
```

**workflow.json**

```json
"Extract_Account":{
   "action":"sfdcDigest",
   "parameters":{
       "fields":[],
       "object":"Account"
   }
}
```

**Result after processing**

If `Account Name`, `Account Source`, and `Industry` are selected:

```json
"Extract_Account":{
    "action":"sfdcDigest",
    "parameters":{
        "fields":[
            {"name":"Name"},
            {"name":"AccountSource"},
            {"name":"Industry"}
        ]
    }
}
```

## Combine Arrays

These functions extend the power of `array:forEach`.

**array:union**

Uses only unique values, so no values are duplicated.

```json
"value": "${array:union(array:forEach(Variables.Account_Fields, '{\"name\": \"${var.fieldName}\"}'),array:forEach(Variables.Account_Fields2, '{\"name\": \"${var.fieldName}\"}'))}"
```

**array:concat**

Two new arrays:

```json
"value": "${array:concat(array:forEach(Variables.Account_Fields, '{\"name\": \"${var.fieldName}\"}'),array:forEach(Variables.Account_Fields2, '{\"name\": \"${var.fieldName}\"}'))}"
```

One new array with an existing array:

```json
"value":"${array:concat(Rules.CurrentNode, array:forEach(Variables.Account_Fields, '{\"name\":\"${var.fieldName}\"}'))}"
```

**Which actions support array functions**

You can use array functions in the `“set”` and `“put”` actions, but not in the `“add”` or `“delete”` actions.

**note:** In `“add”`, the value is being added to an existing array, so the result is an array inside an array, which is not well-formed JSON. To add more array values to an existing array, use `“set”` with the `array:concat` function. For `“delete”`, value is not used.

## Use `StringType` and `NumberType` Arrays

You can use array values from `StringType` the same way as from `NumberType`.

**variables.json**

```json
    "Account_Fields_String": {
       "label": "Pick string fields for your dataset",
       "description": "Multiselect string test",
       "defaultValue": ["Name"],
       "required": true,
       "variableType": {
           "type": "ArrayType",
           "itemsType": {
               "type": "StringType",
               "enums": ["Name", "AccountSource", "Industry", "Type"]
           }
       }
    }
```

**rules.json**

```json
"value": "${array:forEach(Variables.Account_Fields_String, '{\"name\": \"${var}\"}')}"
```

## Replace Multiple Yes/No Widgets

You can also use the multiselect widget to replace multiple `StringType` widgets with `“Yes”` and `“No”` selections. This example uses three `StringType` widgets on one wizard page:

![This image depicts an example of three string types in one wizard page.](https://developer.salesforce.com/docs/media/atf/atf_3stringtypes_1wiz.png)

You can replace this with a single `ArrayType` widget:

![This image depicts an example of replacing three string types with a single arrayType widget.](https://developer.salesforce.com/docs/media/atf/atf_arraytype_widget.png)

The JSON for this variable is:

```json
"SelectedFeatures": {
    "label": "Please select the features you would like to enable?",
    "description": "The selected features for this app",
    "defaultValue": [
    	"Apex Execution"
    ],
    "variableType": {
      "type": "ArrayType",
      "itemsType" : {
        "type" : "StringType",
        "enums" : [
        	"Apex Execution",
        	"API",
        	"Content Transfer",
        	"Dashboard",
        	"Login",
        	"Report Export",
        	"Rest API",
        	"Setup Audit Trail",
        	"UI Tracking",
        	"URI",
        	"Visualforce Request",
        	"Wave Change",
        	"Wave Interaction",
        	"Wave Performance"
        ]
  	  }
    },
    "required": true
  }

```

You can use the selected values to set constants in `rules.json`, which you can then reference in conditionals for actions or in `template-info.json`.

```json
"constants" : [
	{"name":"hasApexExecution", "value": "${array:contains(Variables.SelectedFeatures, 'Apex Execution')}"},
	{"name":"hasAPI", "value": "${array:contains(Variables.SelectedFeatures, 'API')}"},
	{"name":"hasContentTransfer", "value": "${array:contains(Variables.SelectedFeatures, 'Content Transfer')}"},
	{"name":"hasDashboard", "value": "${array:contains(Variables.SelectedFeatures, 'Dashboard')}"},
	{"name":"hasLogin", "value": "${array:contains(Variables.SelectedFeatures, 'Login')}"},
	{"name":"hasReport", "value": "${array:contains(Variables.SelectedFeatures, 'Report Export')}"},
	{"name":"hasRestApi", "value": "${array:contains(Variables.SelectedFeatures, 'Rest API')}"}
]
```

[Back to Rules Overview](https://developer.salesforce.com/docs/analytics/app-template-framework/guide/atf-rules-overview.md)
