Use the following libraries and common code resources compiled here to help you write flows.
Libraries
App Xchange supports the NodeJS v18.15.0 version of JavaScript.
The App Xchange flow engine supports the following JavaScript libraries:
Day.js
Numeral.js
Lodash
uuid
Day.js
View the Day.js library documentation.
V1.11.7
The flow engine supports all methods including the following plugins:
Numeral.js
View the Numeral.js library documentation.
V2.06
The flow engine supports all methods.
Lodash
View the Lodash library documentation.
V4.17.21
All methods are supported. To call lodash functions, use the standard _.method().
uuid
View the uuid library documentation.
V9.0.0
The most common method for generating GUIDs is uuid.v4().
Flow Helpers
The App Xchange flow engine uses the following helper code snippets to help you access data when writing flows. Helpers are organized by the namespaces they access:
workspace
info()
Access data of the Flow Workspace: workspace.info()
Access the Workspace id: workspace.info().id
Access the Workspace name: workspace.info().name
appNetwork
fileUrl(fileId: string)
Generate an App Network file url: appNetwork.fileUrl('fileGuid')
legacyFileUrl(fileId: string)
Generate a Legacy App Network file url: appNetwork.legacyFileUrl('fileGuid')
flow
info()
Access flow info: flow.info()
Access the flow registration ID: flow.info().registrationId
Access the flow URL: flow.info().url
config
Access the flow's configuration: flow.config
Access a property on the flow's configuration: flow.config.myProperty || flow.config[myProperty]
loopItem()
Access item data (only available for a For Each in a List step): flow.loopItem()
mapItem()
Access item data (only available in the context of mapping data in a Map step or Connector Action step): flow.mapItem()
trigger
Access the flow's trigger event: flow.trigger.event
Access the flow's trigger data: flow.trigger.data
Check if the flow run was triggered by a cache record create event: flow.trigger.isCacheCreate()
Check if the flow run was triggered by a cache record update event: flow.trigger.isCacheUpdate()
Check if the flow run was triggered by a cache record delete event: flow.trigger.isCacheDelete()
Check if the flow run was triggered by an action closed out as successful: flow.trigger.isActionSuccess()
Check if the flow run was triggered by an action closed out as failed: flow.trigger.isActionFail()
step(stepId: string)
Access a property on the output data of a previously executed step: flow.step("step-id").output.JobCode
Access the action response of a previously executed step: flow.step("step-id").actionResponse
Access the action request of a previously executed step: flow.step("step-id").actionRequest
Check if a previously executed step has an action status of Success: flow.step("step-id").isActionSuccess()
Check if a previously executed step has an action status of Fail: flow.step("step-id").isActionFail()
Check if a previously executed step has an action status of Queue Action Success: flow.step("step-id").isQueueActionSuccess()
Dates
Return today’s date:
Use Vista standard formatting for batch creation:
Note: Will set to the first day of the current month.
Compare a date to the current day:
Create a date variable, set it equal to an input value, and output it in a specific format:
Safely convert a value to a date, or default to today’s date:
Calculate the next closest Friday after a given date:
Note: Replace the example date with your date variable.
Calculate the last day in a month:
Calculate the last day in a week:
Compare two dates:
Strings
Check if a string contains specified text:
Find the first position of a specified value:
Note: Will return a -1 if not found.
Convert to upper or lower case:
Note: You should convert to lowercase or uppercase prior to string comparison. For example, converting an email address, vendor name, or payment type name to lowercase prior to comparison will make it case-insensitive and protect you against capitalization errors.
Lodash also gives us the following:
Return the length of the string:
Delete or keep part of the string:
Javascript has a substring() method, but we recommend slice(). For more information, read this explanation from Mastering JS.
slice() takes a startIndex and an optional endIndex and returns the string between the start and the end indexes.
If no endIndex is supplied, slice() preserves through the end of the string.
This is non-destructive. It returns a new string from the start index to the end index while leaving the original string intact. vTest remains unchanged. You will have to assign this to a new variable in order to access it.
Replace all instances of a string with another:
Use replace to strip out special characters. It is a non-destructive way to ensure your string is sanitized and does not contain special characters that can cause problems.
Remove starting and ending white space:
Trim should be one of the most common functions used with strings. Use it to get rid of any leading or trailing whitespace that can cause issues. Whitespace has been known to cause support tickets and delays in onboarding, and is very tough to track down. Use Trim and eliminate this headache!
Evaluate if a value is blank or null:
Always check for null or empty prior to using the value. You can then create a hierarchy of data, for example, checking allocation fields first and if blank/null then checking the expense detail fields and if blank/null then defaulting to something. This type of defensive coding keeps flows from failing and remediation tasks from being created for missing data.
Format data as currency:
Split a string into parts:
As with previous JS string methods, these are non-destructive to the original string and must be assigned to new variables.
If the string does not contain the character or string you are splitting on, it returns undefined.
Add characters to the beginning or ending of a string:
Numbers
Parse a number from a string:
Format a number into dollars:
Arrays
Create a hardcoded array, e.g. for use with the In operator in a filter expression.
Caution: Use extreme care when hardcoding anything. Make sure it will never need to be changed.
Determine if any element in an array contain a value matching the criteria:
Determine if all elements of an array contain a value matching the criteria:
Sort an array by a column in descending order and then return the first value (highest value):
sort() mutates the original array. The default sort order is ascending. The time and space complexity of the sort cannot be guaranteed as it depends on the implementation.
Lodash is another option:
Evaluate if a lookup step had any records:
Access an element in lookup:
Map a filter step's output array:
Add each value in an array to a list or a string:
Sum all values in a field of an array or list:
The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.
The first time the callback is run there is no return value of the previous calculation. If supplied, an initial value may be used in its place. Otherwise, the array element at index 0 is used as the initial value and iteration starts from the next element (index 1 instead of index 0). For more information, see this explanation from Mozilla Developer Network.
Assign a value based on looking up a value in an array:
Do something for each item in an array:
Sort the Input for a MAP step, to intentionally order lines in an invoice:
Note: sort() will mutate the original array whereas _.orderBy() will return a new array.
Other Helpful Coding Tips
Create two lists and then find the values from one that does not exist in the other:
Create the two lookup steps
lookup-ineight-employees-ocakj
lookup-vista-employees-xy6c9
Create the filter step
List
Test Expression
Use null coalesce (double question marks):
Note: These are both the same.
How to fix if node does not contain something:
Note: Reference the . before ["Concur_Approver"].
Use regex for any file containing KPC and ending in .CSV:
Call a configured variable:
If the variable is a single object
If the variable is a Multiple Text Items
Reference a configuration property set as multiple text items:
Check if the Configuration Value is empty:
Create a map step without any input:
Set “List or Object” [] or {}
Dynamically determine start row for a Parse Delimited File step:
You have to edit the JSON of the flow, but then you can change the property to any value you want. Must resolve to a number.
StartingRowNumber:
Create a random string:
TryParse:
Set the field to get data from via a configuration:
Note: This is helpful if you want to use a configuration on a shared flow to set a different ud field to reference for each customer.
Everything inside the brackets is just a string value, so this method can be used in a number of ways.
You can also create other dynamic situations.