C# to JavaScript Conversions
Use the following code snippets to help you switch from writing flows in C# to writing flows in JavaScript.
DateTime
Return today's date in
Return today's date in C#:
DateTime.Now.Date
Return today's date in JS:
dayjs();
Compare a date to the current date in
Compare a date to the current date in C#:
DateTime.Parse(Data["Transaction_Date"].ToString())
.Date ==DateTime.Now.Date
Compare a date to the current date in JS:
dayjs().isSame(dayjs(
flow.trigger.data["Transaction_Date"])
);
Safely convert a value to a date, or default to today’s date in
Safely convert a value to a date, or default to today’s date in C#:
// creates new DateTime called dt and sets a default
// to today’s date
var dt = System.DateTime.Now;
bool vIsValidDate = System.DateTime.TryParse(
Data.payRateEffectiveDate?.ToString(),
out dt
);
// If the date parsing fails for any reason,
// set it to a default
if (!vIsValidDate) dt = System.DateTime.Now;
return dt.ToString("yyyy-MM-dd");
Safely convert a value to a date, or default to today’s date in JS:
const dateObj = dayjs(flow.trigger.data
.payRateEffectiveDate);
if (dateObj.isValid()) {
return dateObj.format('YYYY-MM-DD');
}
return dayjs().format('YYYY-MM-DD');
Calculate the next closest Friday after a given date. Replace the example date with your date variable
Calculate the next closest Friday after a given date. Replace the example date with your date variable in C#:
DateTime dt = DateTime.Parse("9/29/2021");
if (dt.DayOfWeek.ToString() != "Friday")
{
int x = System.DayOfWeek.Friday - dt.DayOfWeek;
DateTime Friday = dt.AddDays(x);
return Friday;
}
else
{
return dt;
}
Calculate the next closest Friday after a given date. Replace the example date with your date variable in JS:
dayjs('9/29/2021').day(5);
Calculate the last day in a month
Calculate the last day in a month in C#:
DateTime dt = DateTime.Parse(Data.postedDate);
return new DateTime(
dt.Year,
dt.Month,
DateTime.DaysInMonth(dt.Year, dt.Month)
);
Calculate the last day in a month in JS:
dayjs(flow.trigger.data.postedDate).endOf('month');
Calculate the last day in a week
Calculate the last day in a week in C#:
var culture = System.Threading.Thread.CurrentThread
.CurrentCulture;
var difference = dt.DayOfWeek - culture.DateTimeFormat
.FirstDayOfWeek;
if(difference < 0) {
difference += 7;
}
DateTime start = dt.AddDays(-difference).Date;
return start.AddDays(6).Date;
Calculate the last day in a week in JS:
dayjs(flow.trigger.data.postedDate).endOf('week');
Compare two dates
Compare two dates in C#:
var syncStart = GetConfigValue("syncStartDate");
if (syncStart != null)
{
if (DateTime.Parse(syncStart.ToString()) > DateTime
.Parse(Data.DateCreated.ToString()))
{
return true;
}
}
Compare two dates in JS:
const syncStart = flow.config.syncStartDate;
if (syncStart) {
// greater than
if (dayjs(syncStart) > dayjs(flow.trigger.data
.DateCreated)) {
return true;
}
// isAfter
if (dayjs(syncStart).isAfter(dayjs(flow.trigger.data
.DateCreated))) {
return true;
}
};
Use Vista standard formatting for batch creation (set to 1st day of current month)
Use Vista standard formatting for batch creation (set to 1st day of current month) in C#:
new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1)
.ToString("yyyy-MM-dd")
Use Vista standard formatting for batch creation (set to 1st day of current month) in JS:
dayjs().date(1).format('YYYY-MM-DD');
Create a DateTime variable, set it equal to an input value, and output it in Vista format
Create a DateTime variable, set it equal to an input value, and output it in Vista format in C#:
DateTime dt;
dt = DateTime.Parse(
Data.Items[0].TransactionDate.ToString()
);
return new DateTime(dt.Year, dt.Month, 1)
.ToString("yyyy-MM-dd")
Create a DateTime variable, set it equal to an input value, and output it in Vista format in JS:
dayjs(flow.trigger.data.Items[0].TransactionDate)
.format('YYYY-MM-DD');
Strings
string vTest = "App Xchange, is cool";
Determine if a string contains specified text
Determine if a string contains specified text in C#:
vTest.Contains("sti")
Determine if a string contains specified text in JS:
vTest.includes('sti');
Find the first position of a specified value in C#:
vTest.IndexOf("u")
Find the first position of a specified value in JS:
vTest.indexOf('u');
Convert to upper or lower case in C#:
vTest.ToUpper() or vTest.ToLower()
Convert to upper or lower case in JS:
vTest.toUpperCase() or vTest.toLowerCase();
Return the length of the string
Return the length of the string in C#:
vTest.Length
Return the length of the string in JS:
vTest.length;
Delete all characters from specified index to end
Delete all characters from specified index to end in C#:
vTest.Remove(5)
// vTest = "App X"
Remove()
takes a
startIndex
and an optional count. If no count is provided, it
removes through the end of the string.This is destructive. It is
deleting any characters after the start index. vTest
is changed
and overwritten, and the next time you access it, it will be the shortened
string value.
Delete all characters from specified index to end in JS:
const updatedStr = vTest.slice(0, 5);
const slicedStr = vTest.slice(5)
// vTest = 'App Xchange, is cool';
// updatedStr = 'App X'
// slicedStr = 'change, is cool'
Slice()
and Remove()
are
essentially opposites but can be used to the same effect. With slice you tell it
what to keep.-
Slice()
takes astartIndex
and an optionalendIndex
, but unlikeRemove()
, it returns the string between the start and the endindexes
, whereasRemove()
removes. -
If no
endIndex
is provided,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 have to assign this to a new
variable in order to access it.
Replace all instances of a string with another in C#:
string money = "$3.00";
money.Replace("$", string.Empty)
Replace all instances of a string with another in JS:
const money = '$3.00';
money.replace('$', ''); => '3.00'
Return part of the string
Return part of the string: in C#:
vTest.Substring(0,5) => "App X"
vTest.Substring(vTest.IndexOf("A"), 2) => "Ap"
// Prevents failure when string is less than the end
// index value
vTest.Substring(0,Math.Min(3,vTest.Length)) => "App"
Math.Min
, your code will fail.To avoid a blind substring call:
string pse = Data.Phase.ToString().Trim();
return pse.Substring(0,System.Math.Min(7, pse.Length));
Safe substrings and knowing max values:
You should know what the max value is and protect against truncation. Alternatively,
if using a substring to get the first X characters, you need to protect against the
Math.Min
being smaller.
Data.description.ToString().Substring(
0, Math.Min(Data.description.ToString().Length, 60)
) ?? ""
Return part of the string: in JS:
vTest.slice(0, 5) => 'App X'
vTest.slice(vTest.indexOf('A'), 2) => 'Ap'
// Prevents failure when string is less than the end
// index value
vTest.slice(0, Math.min(3, vTest.length)) => 'App'
// or even simpler
vTest.slice(0, 3 || vTest.length) => 'App'
substring()
method, use slice()
instead. To learn why, see this article on
JavaScript substring() vs slice().Remove starting and ending white space
Remove starting and ending white space in C#:
vTest.Trim()
Remove starting and ending white space in JS:
vTest.trim()
Evaluate if a string is blank or null
in C#:
string.IsNullOrWhiteSpace(Data.Overhead_Expense
.ToString())
//Alternatively, you can use IsNullOrEmpty like this:
if (!string.IsNullOrEmpty(ExpenseDetail.ReportEntryCustom3)) {
vResult = ExpenseDetail.ReportEntryCustom3;
}
in JS:
if (vTest) {
// true when vTest is non-empty string,
// is also true if only whitespace
}
if (vTest.trim()) {
// same as above but fails if only whitespace
}
Format data as currency
Format data as currency in C#:
Data.Amount = "4.35615676"
String.Format(
"{0:0.00}", decimal.Parse(Data.Amount.ToString())
)
Format data as currency in JS:
numeral('4.35615676').format('$0,0[.]00');
Split a string into parts
Split a string into parts in C#:
vTest.Split(",")[0]
vTest.Split(",")[1]
if (vTest.Contains(","))
{
vReturn = vTest.Split(",")[1];
}
if (vTest.Contains("YOUR MOM"))
{
vReturn = vTest.Split("YOUR MOM")[1];
}
Contains
prior to a split to check
that your string contains the character or string you are splitting on.Split a string into parts in JS:
vTest.split(',')[0]
vTest.split(',')[1]
if (vTest.includes(',')) {
vReturn = vTest.split(',')[1];
}
if (vTest.includes("YOUR MOM")) {
vReturn = vTest.Split("YOUR MOM")[1];
}
If the string does not contain the character or string you are
splitting on, it returns undefined
.
Add characters to the beginning or end of a string
Add characters to the beginning or end of a string in C#:
// The number specifies the total desired string length
vTest.PadLeft(20)
vTest.PadLeft(20, "*")
vTest.PadRight(20, "-")
Add characters to the beginning or end of a string in JS:
vTest.padStart(20);
vTest.padStart(20, '*');
vTest.padEnd(20, '-');
Arrays
Arrays are used to store multiple values in a single variable, instead of declaring separate variables for each value. Flows also rely upon the JArray Class, which represents a JSON array, in the Newtonsoft.Json assembly. See more info at JArray Class.
Arrays are much easier to work with in JavaScript than C#.
Create a hardcoded array
In
operator in a Filter
step.in C#:
new int[] {10,15}
new string[] {"Approved", "Variance Approved"}
in JS:
const intArr = [10, 15];
const stringArr = ['Approved', 'Variance Approved'];
Convert a list output to a JArray
Convert a list output to a JArray in C#:
JArray.FromObject(
(Object)Step("convert-file-to-json").Output
)
JArray.FromObject((object)Step("lookup-project-number").Output).Where(r => r["project-number"]?.ToString()
Convert a list output to a JArray in JS:
flow.step('convert-file-to-json').output;
Determine if any element in an array satisfies a requirement
Determine if any element in an array satisfies a requirement in C#:
var hasOwnerAssignee = JArray.FromObject(
(object)Data.Assignees
)
.Where(a => domains.Any(
d => a["ContactEMail"].ToString().EndsWith(d.ToString()))
)
.Any();
Determine if any element in an array satisfies a requirement in JS:
const hasOwnerAssignee = flow.trigger.data.Assignees
.some((a) => domains.some(
d => a.ContactEMail.endsWith(d)
),
);
Sort an array by a column in descending order and then return the first value (highest value)
Sort an array by a column in descending order and then return the first value (highest value) in C#:
JArray.FromObject((object)Data.Items)
.OrderByDescending(x=>int.Parse(x["Hubometer_Reading"].ToString()))
.First()["Hubometer_Reading"]
.ToString()
int.Parse
. Change it to a
TryParse
instead. Decimals, dates, and integers all need to be
TryParse
.Int32.TryParse(
item.GLCo.ToString(), out Int32 glco);
Sort an array by a column in descending order and then return the first value (highest value) in JS:
flow.trigger.data.Items.sort(
(a, b) => b['Hubometer_Reading'] - a['Hubometer_Reading']
)[0];
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:
// Lodash
const sorted = _.orderBy(flow.trigger.data.Items, 'Hubometer_Reading',
'desc')[0];
Evaluate if a lookup step has any records
Evaluate if a lookup step has any records in C#:
((IEnumerable<dynamic>) Step("lookup-employee").Output)
.Any()
To access element in lookup:
if (Step("lookup-job-in-spectrum").Output.Count > 0)
{
return Step("lookup-job-in-spectrum").Output[0]
.Job_Number.ToString();
}
else
{
return (string)null;
}
if exists
check before using the output.Evaluate if a lookup step has any records in JS:
flow.step('lookup-employee').output.length > 0
// Lodash
_.any(flow.step('lookup-employee').output)
To access element in lookup:
if (flow.step('lookup-employee').output.length > 0) {
return flow.step('lookup-employee').output[0].Job_Number.toString()
} else {
return null;
}
Make sure all lines of a JArray/array contain a value matching the criteria
Make sure all lines of a JArray/array contain a value matching the criteria in C#:
JArray x = JArray.FromObject(Step("convert-to-json").Output)
return x.All(i => i["Employee_Id"].ToString() != "")
Make sure all lines of a JArray/array contain a value matching the criteria in JS:
flow.step('convert-to-json').output
.every(i => i["Employee_Id"]);
Cast the dynamic object from a filter step's output to an object so you can turn it into a JArray
Cast the dynamic object from a filter step's output to an object so you can turn it into a JArray in C#:
JArray.FromObject(
(object)Step(“filter-vista-employee-list-yx5mr”)
.Output
)
// then we can use JArray functions on it
JArray.FromObject(
(object)Step("filter-vista-employee-list-yx5mr")
.Output
)
.Select(x => x["SourceSystemId"].ToString())
.ToArray()
Cast the dynamic object from a filter step's output to an object so you can turn it into a JArray in JS:
flow.step('filter-vista-employee-list-yx5mr').output
.map(x => x.SourceSystemId);
Add each value in an array to a list or a string
Add each value in an array to a list or a string in C#:
string results = "";
foreach (var flag in Data.flags[0].system_flag_details)
{
if (flag["reasons"] != null && flag[“reasons”] != "")
{
results += $”{flag[“reasons”]}: “;
}
}
return results;
Add each value in an array to a list or a string in JS:
let results = '';
flow.trigger.data.flags[0].system_flag_details.forEach(flag => {
if (flag.reasons) {
results += `${flag.reasons}: `
}
})
return results;
Sum all values in a field of an array or list
in C#:
JArray.FromObject(
(Object)Step(“lookup-class”).Output.DednLiabs)
.Sum(x=>x.decimal.Parse(x[“NewRate”])
);
in JS:
const values = flow.step('lookup-class').output.DednLiabs
values.reduce(
(prev, curr) => prev + Number(curr.NewRate),
0
);
// Numeraljs
values.reduce(
(prev, curr) => numeral(prev).add(curr.NewRate).value(),
0
);
// Lodash
_.sumBy(values, (e) => Number(e.NewRate));
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.
See the Mozilla developer docs for more information on the reduce() method.Assign a value based on looking up a value in an array
Assign a value based on looking up a value in an array in C#:
var rate = JArray.FromObject(
(Step("lookup-class").Output[0].PayRates as JArray)
.Where(
e => e["Shift"].ToString() ==
Step("lookup-employee-in-vista").Output.Shift
.ToString()
)
.ToArray());
Assign a value based on looking up a value in an array in JS:
const payRates = flow.step('lookup-class').output[0]
.PayRates;
const shiftToMatch = flow.step('lookup-employee-in-vista')
.output.Shift;
// if there can be multiple matches, use filter()
const rates = payRates.filter(e => e.Shift === shiftToMatch);
// if you only want to match on the first successful hit,
// use find()
const rate = payRates.find(e => e.Shift === shiftToMatch);
Determine if an object in an array has a field
Determine if an object in an array has a field in C#:
var x = JArray.FromObject((object)Data);
foreach(JObject item in x)
{
if(item.ContainsKey(“department”))
{
// do something
}
}
Determine if an object in an array has a field in JS:
flow.trigger.data.forEach(item => {
if (item.department) {
// do something
}
})
Sort the input for a Map step to intentionally order lines in an invoice
Sort the input for a Map step to intentionally order lines in an invoice in C#:
JArray sorted = new JArray(lines.OrderByDescending(
x=>x["Equipment"].ToString()
)
);
return sorted;
Sort the input for a Map step to intentionally order lines in an invoice in JS:
lines.sort((a, b) => {
if (b.Equipment > a.Equipment) return 1;
if (b.Equipment < a.Equipment) return -1;
return 0;
});
// Lodash
const orderedLines = _.orderBy(lines, 'Equipment', 'desc');
sort()
mutates the original array, whereas
_.orderBy()
returns a new array.Was this helpful? Give us feedback.