LogoLogo
Back to studio
  • Formsort documentation
  • ⏩Quickstart
    • 🟒Get started with Formsort
    • 🍎Core concepts
    • ℹ️Question and content reference
    • πŸ“•Key terms
    • 🏞️Create your first flow
    • πŸ“–Add content and collect answers
      • 🀳Capture demographic data
      • ℹ️Add informational content
      • πŸ” Review your variable schema
    • 🎨Create a theme
      • Set brand guidelines
    • 🀹Personalize your flow
      • 🌟Template your variables
      • 🧠Add conditional logic
      • πŸ’«Using conditional logic with Calculated and API variables
      • πŸ”šEnd the flow
    • πŸ”€Set up integrations
    • πŸš€Go live
      • Auditing your flow for content, functionality, and design
    • πŸ’ΌCommon use cases
      • πŸ’”Disqualify responders
      • πŸ—“οΈAdd a scheduling option
      • πŸ“„Allow responders to read and accept your company policies
  • πŸ—οΈBuilding flows
    • Flows and variants
      • Flow starts
    • Adding content
      • Groups
      • Steps
        • Settings
        • Logic
        • Style
      • Questions
        • General Settings
        • Style
        • Address
        • Comparison
        • Confirmation
        • Date
        • Date & Time
        • Email address
        • File upload
        • Grid choice
        • Iframe
        • Image upload
        • Number
        • Payment
        • Phone number
        • Postal code
        • Question group
        • Region
        • Select
          • Providing choices via API or calculation
        • Signature
        • SSN
        • Text questions
        • Yes/No
      • Content
        • General Settings
        • Statement
        • Image
        • Video
        • Next button
        • Divider
        • Map
      • Endings
      • Using markdown
      • Using variable templating
        • Template formatting functions
      • Copy-pasting form content
      • Content library
    • Conditions and logic
      • Logical operator reference
      • Advanced logic
    • Variables (answers)
      • Variables from questions
      • Externally provided variables
      • Calculated variables
      • API lookups
      • System Library variables
      • Orphaned variables
    • Schemas
      • JSON Schemas
      • Validating flow schemas
    • Redirects
    • Styling and themes
      • CSS Reference
      • Overriding theme styling
      • Custom CSS overrides
      • Content area
      • Animations and transitions
      • Form Layout
      • Typography
        • Adobe Fonts
        • Hosting custom fonts
      • Color variables
      • Dimension variables
      • Question containers
      • Assets
      • Form Buttons
        • Select buttons
      • Inputs and dropdowns
      • Checkmarks
      • Tables
      • Sliders
      • Divider lines
      • Progress bar
      • Comparison cards
    • Variant settings
      • Form behavior for returning responders
      • Group ranking API
    • Publishing and versions
      • Preview window
      • Deploying
      • History
  • πŸ’ΎHandling data
    • Philosophy and data retention policy
    • Viewing form answers
    • Responder UUIDs
    • Environments
      • Loading different environments
    • Passing data in
      • URL parameters
      • POST body
      • Embed query parameters
    • Custom validators
    • Form answers and events
      • Analytics events
      • Signed requests
      • Event payload shape
      • Submission frequencies
      • Runtime error reporting
      • Admin API
      • Flow content data format
    • Integration reference
      • Amplitude
        • Amplitude cross domain tracking
      • BigQuery
      • FullStory
      • Google Analytics
        • Updating from Universal Analytics to GA4
      • Google Cloud Storage
      • Google Sheets
      • Google Tag Manager (GTM)
        • JavaScript triggered by flow events
      • Hubspot
      • Jornaya
      • Optimizely
      • PostgreSQL
      • Redshift
      • Rudderstack
      • S3
      • Salesforce
      • Segment
        • Segment Setup
        • Segment cross domain tracking
      • Stripe
      • TrustedForm
      • Webhooks
        • Zapier
  • πŸ“ΊGoing live
    • Custom domains
    • Built-in analytics
    • Embedding
      • Web-Embed API
        • React-embed
      • Adding authentication
      • Embedding forms in iOS and Android
      • Setting up a dev environment
    • Split testing
    • Preflight checklist
  • 🏒Teams
    • Accounts
      • Roles and permissions
    • Events subscriptions
    • Workspace domain detection
Powered by GitBook
On this page
  • Adding a calculated answer
  • Variable type
  • Is array?
  • Getter function body
  • Optional Variables
  • When are calculated variables evaluated?
  • Conditional evaluation
  • Re-calculate on load
  • Useful calculated variable function examples

Was this helpful?

  1. Building flows
  2. Variables (answers)

Calculated variables

Create derived variables by writing functions optionally using other variables

PreviousExternally provided variablesNextAPI lookups

Last updated 2 months ago

Was this helpful?

Calculated variables allow you to define and calculate new answers based on other answers present within the flow, by writing simple functions that are evaluated within Formsort.

Common uses of calculated variables include:

  • Formatting answers

  • Capturing conditional logic that cannot be easily expressed

  • Performing math on numbers or dates

Calculated variables behave just like any other answer: they can be used for , into most text, and are sent to your analytics and integrations.

Adding a calculated answer

From the Variable tab, select Calculated variables, and click Add calculated variable...

Variable type

Sets the expected that we are expecting the calculation to return: string, number, or boolean

Is array?

If Is array? is enabled, then we will expect the response to contain multiple answers.

Getter function body

The Getter function body contains the Typescript code function body for the calculated answer.

For example, the following getter function body will result in the date 6 months from the current date:

// Getter function body
function myFunction(): string {
  const today = new Date();
  const d = today.getDate();
  const future = new Date(today.setMonth(today.getMonth() + 6));
  if (future.getDate() != d) {
    future.setDate(0);
  }
  return future.toLocaleDateString();
}

To use existing answers within a getter function body, add the answers as variables. The following calculated variable will calculate the length of the answer variable labelled first_name

The myFunction() { ... } part of the getter function body is auto-generated and cannot be modified.

Optional Variables

If any of the parameters to myFunction are optional, such as in the case of API variables that may or may not be passed in, make sure to check the Optional field next to the variable.

If a variable that is not optional is not passed to the function, the Getter function will not execute correctly!

When are calculated variables evaluated?

If a calculated variable has no answer dependencies, it is evaluated at the time that the flow loads.

For calculated variables with dependencies, by default, calculated variables are only evaluated once all of their required (non-optional) input variables are defined. If any of the required input variables become undefined, the calculated variable is cleared.

// Getter function body
return Math.max({{number_a}}, {{number_b}});

If only one or none of the input answers are defined, largest_number will remain undefined.

number_a: undefined
number_b: undefined

largest_number: undefined

---

number_a: 17
number_b: undefined

largest_number: undefined

Only when all of the input answers are defined will the calculation occur.

number_a: 17
number_b: 48

largest_number: 48

For calculated variables with optional dependencies, the calculated variables will be evaluated before the optional dependencies have a value, and will then be re-evaluated whenever an optional dependency receives a value, such as in the case of a responder providing a value for an answer variable.

Blocks advancing from current step?

Enabling Blocks advancing from current step? in the configuration menu of your calculated variable will prevent the user from advancing past a step until calculations are finished processing. If no calculations have started yet (i.e. not all the dependencies are in), the step will not wait for the variable and the user will proceed. This ensures that calculated variables are present as the user proceeds through the flow, which helps to prevent logic errors down the line, and maintains data fidelity in the answers sent to your endpoint.

Conditional evaluation

When using conditional evaluation, you must take care to handle undefined answers within the getter function body.

// Condition for either number_a OR number_b being defined
{
  "$or": [
    "number_a": { "$exists": true },
    "number_b": { "$exists": true },
  }
}

Now that we're evaluating the calculation even when the inputs are undefined, we need to change the getter function body to handle this case.

// Getter function body
if ({{number_a}} === undefined) {
  return {{number_b}};
} else if ({{number_a}} === undefined) {
  return {{number_a}};
}
return Math.max({{number_a}}, {{number_b}});

Re-calculate on load

If a calculated variable was calculated in a previous session, and the responder returns to the flow, the default behavior is not to re-calculate the answer.

To always recalculate the answer on load, enable Re-calculate on load. This is useful for situations when calculated variables are not idempotent, meaning that repeated invocations do not result in the same result, such as answers depending on the current date or time.

Unless you need the variables in the answer's payload, avoid using this option as it has performance implications. Step conditional logic waits for calculated variables by default. Don’t use this option to ensure the conditional logic within the form is applied correctly.

Useful calculated variable function examples

Get age from DOB

We can calculate a responder's age based on the date they enter for answer variable patient_dob in this example.

function myFunction(patient_dob: string): number { //readonly line
  const birthDate = new Date(patient_dob);
  const today = new Date();

  let age = today.getFullYear() - birthDate.getFullYear();

  // Check if the birthday has already occurred this year
  const hasBirthdayPassed =
    today.getMonth() > birthDate.getMonth() ||
    (today.getMonth() === birthDate.getMonth() && today.getDate() >= birthDate.getDate());

  if (!hasBirthdayPassed) {
    age--; // Subtract 1 if the birthday hasn't happened yet this year
  }

  return age;
}

Calculate amount of days from today

Using this function, we can calculate the amount of days that have (or will) elapse from a date before or after today.

function myFunction(user_defined_date: string): number { // readonly line
  // turns dates (user_defined_date, today) into ms
  const date1 = new Date(user_defined_date)
  const date2 = new Date()

  // one day in ms 
  const oneDay = 1000 * 60 * 60 * 24

  // calculates time difference between two dates, in ms
  const timeDiffInMs = date2.getTime() - date1.getTime()

  // converts ms to days
  const diffInDays = Math.round(timeDiffInMs / oneDay)

  // return absolute value of the number
  // prevents negative number returns 
  return Math.abs(diffInDays)
}

Check responder answer against a list

This function will return a boolean true/false value, based on whether or not the responder's answer to State is included in a list.

function myFunction(State: string): boolean { // readonly line
  const ineligibleStates = ["DE","HI","LA","MD","MA","NV","NJ","NM","NC","OH","OR","RI","SC","SD","TX","UT"]
   if (ineligibleStates.includes(State)) {
    return true 
  }
  return false 
}

Calculate BMI

This function requires a height and weight input, and will return a calculation of the users Body Mass Index.

function myFunction(
  height_ft: string, 
  height_in: string, 
  weight_lbs: string
): number { // readonly line
// Convert height to meters
const heightMeters = (parseInt(height_ft)*12 + parseInt(height_in)) * 0.0254;
//Calculate and round
const bmi = Math.round(parseInt(weight_lbs) * 0.45359237 / (heightMeters ** 2) * 10) / 10;
return bmi;
}

For more examples on creating calculating variables, see at the bottom of this page.

Imagine the following calculated answer, which uses the javascript function to find the larger of two numbers, and we'll call largest_number:

Calculated variables are handled asynchronously, and the default calculated variable configuration does not guarantee that the variable will be available by the time answer payloads are submitted. For instance, if a calculated variable finally receives the dependencies it needs on a step that will also send a payload (see ), the user might advance past the step before the calculated variable has time to finish it's calculations and attach the result to the payload, resulting in a seemingly missing calculated variable.

For more control over when the calculated variable is evaluated, you can set a using Is conditional?

Using the above example of largest_number, we could add a condition using to run the calculation whenever either number is defined.

πŸ—οΈ
Math.max
submission frequency
condition
Advanced logic
Useful calculated functions
conditions
templated
data type