Use Array Functions for Multi-Select Widgets and Looping
The following code
"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:

The ArrayType variable contains an itemsType attribute, which accepts the following:
- SObjectType
- SObjectFieldType
- DatasetType
- DatasetDateType
- DatasetDimensionType
- DatasetMeasureType
- StringType, or
- NumberType
The widget places values in an array. The following show how the widget displays values for the user to select:


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:
- ${Variables.Account_Fields[0]} returns (sobjectName=Account, fieldName=Name, sobjectLabel=Account, fieldLabel=Account Name)
- ${Variables.Account_Fields[0].fieldName} returns Name
- ${Variables.Account_Fields[0].fieldLabel} returns Account Name
- fieldName is required for dataflow
The selection values from the widget are stored in the variable and there are two ways to access them in the template files (rules, dashboards, workflow):
- Use array values from SobjectFieldType without looping, accessing by
index
"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.
- Use array values from SobjectFieldType with looping via the array:forEach function. In this example, a “set” action is going to loop through the SObjectFieldTypes in the array and add them to the “fields” attribute in the Extract_Account step of the workflow. Each entry in “fields” will need “name” and “var.fieldName”.
-
-
rules.json
"name": "AddAccountFilesToDataflow", "appliesTo": [ { "type": "workflow", "name": "*" } ], "actions": [ { "action": "set", "description": "use selected values for sfdcDigest in dataflow", "path": "$.workflowDefinition.Extract_Account.parameters.fields", "value": "${array:forEach(Variables.Account_Fields, '{\"name\": \"${var.fieldName}\"}')}" } ]
-
dataflow.json
"Extract_Account":{ "action":"sfdcDigest", "parameters":{ "fields":[], "object":"Account" } }
- Results after processing if Account Name, Account Source, and Industry are
selected
"Extract_Account":{ "action":"sfdcDigest", "parameters":{ "fields":[ {"name":"Name"}, {"name":"AccountSource"}, {"name":"Industry"} ] } ]
-
rules.json
Here are more ways to work with arrays that extend the power of the array:forEach function:
-
array:union (only uses unique values, so no duplicated
values)
"value": "${array:union(array:forEach(Variables.Account_Fields, '{\"name\": \"${var.fieldName}\"}'),array:forEach(Variables.Account_Fields2, '{\"name\": \"${var.fieldName}\"}'))}"
-
array:concat (2 new
arrays)
"value": "${array:concat(array:forEach(Variables.Account_Fields, '{\"name\": \"${var.fieldName}\"}'),array:forEach(Variables.Account_Fields2, '{\"name\": \"${var.fieldName}\"}'))}"
-
array:concat (1 new array with existing
array)
"value":"${array:concat(Rules.CurrentNode, array:forEach(Variables.Account_Fields, '{\"name\":\"${var.fieldName}\"}'))}"
- You can use array functions in the “set” and “put” actions,
but not in the “add” or “delete”.
- 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 array values from StringType (same for NumberType)
-
variables.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
"value": "${array:forEach(Variables.Account_Fields_String, '{\"name\": \"${var}\"}')}"
-
variables.json
- You can also use the multiselect widget to replace the current use of multiple StringType widgets with “Yes”
and “No” selections. The following is an example using
three StringType widgets on one wizard page:
You can replace this with a single ArrayType widget:
The JSON for this variable is:
"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.
"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')}"} ]