Skip to content
English
  • There are no suggestions because the search field is empty.

How to use the function element

What it is

The Function element lets you write a small piece of JavaScript directly into a flow to calculate a value from other answers, the report subject, loop data, or workflow parameters. It's designed to replace chains of multiple Calculation elements with a single, flexible scripting step — the result is stored as the element's own answer, so it can feed routing logic or be picked up by other elements just like any other answer.

When to use it

Use a Function element any time you need to turn raw answers captured on the floor into a calculated result — and then do something with that result, like routing to a different step, triggering a follow-up action, or flagging something for review.

Common examples:

Quizzes and training checks — score a set of questions and route operators who fail below a threshold to a retake or a supervisor review step
Health and safety checklists — calculate a pass/fail or percentage-complete score from a set of checklist items, and trigger an escalation if it falls below an acceptable level
Equipment or line readiness checks — combine several individual readings or checks into one overall status that decides what happens next in the flow
Rolled-up totals from a Content Loop — e.g. total defects found across every unit inspected, used to decide whether the batch passes or needs a hold
Any multi-step calculation with conditional logic — where a single Calculation element isn't enough, and chaining several together is getting hard to follow

The common thread: it's not just about producing a number, it's about that number driving something — routing, a visibility trigger, or a value another element downstream needs to act on.

How it behaves

  • Runs a sandboxed subset of JavaScript (ES5) — no network access, no external libraries beyond what's documented below.
  • Recalculates automatically as the answers it depends on change; there's no manual "calculate" step.
  • return is optional — if the last line is a plain value or variable, it's returned automatically.
  • Works identically online and offline in the mobile app.
  • Can be marked Hidden, so it calculates and stores a value without being shown to the operator — useful for helper calculations that feed other logic.

Reading answers 

Use answer() for a single value, or answers() for an array of values matching an element tag.

Doubling a numeric reading:

answer("temp reading") * 2

If the operator entered 42 for "temp reading", this returns 84.

Checking a single yes/no answer:

answer("ppe check") === "Yes" ? "Pass" : "Fail"

If "ppe check" was answered "Yes", this returns "Pass". Anything else returns "Fail".

Pulling every answer for a repeated question:

answers("defect count")

If the same "defect count" question was answered three times (e.g. once per unit in a loop), this returns an array of the raw values, e.g. [2, 0, 1] — not a total, just the list.

Counting how many times something was answered:

answers("result").length

If "result" was answered 8 times across a step, this returns 8.

Scoping — filtering which answers to read

By default answers() reads across the whole report. You can narrow the scope with a second argument:

 

EXPRESSION

WHAT IT DOES

answers("tag", { scope: Scope.loopIteration })

Only answers within the current content-loop iteration

answers("tag", { scope: Scope.local })

Only answers in the same section as this Function element

answers("tag", { step: "Step label" })

Only answers from elements in a specific step

answers("tag", { type: "number" })

Only answers from number-type elements

Example: Narrowing to one specific step:

Add the name of your step after your tag within the answer/answers callout.

answer("pressure", { step: "Final inspection" })

This only looks at the "pressure" answer from the "Final inspection" step, ignoring any earlier steps that might reuse the same tag.

Working with Content Loops

Example: Scoping to the current iteration — inside a Content Loop capturing dimensions per unit:

answer("length", 
{ scope: Scope.loopIteration }) * answer("width",
{ scope: Scope.loopIteration })

For a unit with length 4 and width 2.5, this returns 10 — just that unit's area, not mixed with any other unit in the loop.

Example: Rolling up across every iteration — place the function element outside the loop, after the loop has finished:

sum(answers("defect count"))

If the loop ran 5 times with defect counts of [2, 0, 1, 0, 3], this returns 6 — the total across the whole batch.


Example: Reading the current loop unit's own data:

loop.subject.name + ": " + loop.subject.data["Line"]

For a loop currently on the unit "Pallet 12" with a "Line" property of "Line 3", this returns "Pallet 12: Line 3".

Report subject and parameters

 

subject — the report subject unit

 

subject.name  - display name

subject.data[“Unit attribute name”] - data attributes

subject.idc.maximoID -  external ID

 

loop — the current loop iteration's subject

 

loop.subject.name - loop subject display name

loop.subject.data[“Unit attribute name”] - loop subject data attributes

 

param() — workflow parameters

Returns the unit passed into the flow as that parameter. Note: custom properties are under .prop here, not .data.

 

param("target_sku").name

param("target_sku").prop.product_name

param("line").idc.externalId

 

user — the person filling in the report

 

user.name

user.email

Example - Comparing a target against a captured answer:

subject.data["target_weight"] - answer("measured weight")

If the subject's target weight is 500 and the operator measured 485, this returns 15 — how far under target the unit came in.

Reading a workflow parameter:

param("shift").name

If this report was run under the "Night Shift" parameter, this returns "Night Shift".

Built-in math functions

Average of a set of readings:

mean(answers("pressure"))

For pressure readings of [100, 102, 98], this returns 100.

Highest reading captured:

max(answers("temp"))

For temperatures of [68, 72, 70], this returns 72.

Scrap percentage, rounded to one decimal:

round(
(sum(answers("scrap count")) / sum(answers("units produced")))
* 100, 1)

For 15 scrapped units out of 500 produced, this returns 3.0.

Standard deviation of a set of measurements:

std(answers("fill weight"))

Useful for spotting inconsistent filling across a batch — returns a single number representing the spread of the values.

map, filter, forEach, and sort are also available if you need to pre-process an array of answers before aggregating it.

Example: scoring a set of yes/no questions

var scores = answers("checklist item").map(function (value) {  
return value === "yes" ? 1 : 0; });
return round((sum(scores) / scores.length) * 100, 1);

For 10 checklist items where 7 were answered "yes", this returns 70.0.

Things to keep in mind

  • Syntax is ES5 only — use var and function(){} rather than let, const, or arrow functions.
  • Comparisons are case-sensitive — check the exact text your answer options use (e.g. "Yes" vs "yes") before comparing.

Troubleshooting

My function returns 0 or an empty result, even though answers have been captured.
This usually means answers() or answer() isn't matching anything. First, temporarily return the raw call on its own — e.g. return answers("your tag"); — and check what comes back:

  • If it's an empty array [], the tag doesn't match any element. Double check the exact tag spelling on the source elements in the flow builder; tags are case-sensitive.
  • If it's not empty but your calculation still returns 0, inspect one value directly (e.g. return answers("your tag")[0];) and compare it to what your code is checking for.

My yes/no (or text) comparison isn't matching, even though the answer looks right.
Comparisons like === "Yes" are case-sensitive. If the actual captured value is "yes", "YES", or has extra spacing, the comparison will silently fail rather than error. Use .toLowerCase() on the value before comparing, or inspect the raw value first to see exactly what's being stored.

My loop-scoped calculation is picking up data from other iterations.
Make sure every answer()/answers() call inside the loop uses { scope: Scope.loopIteration }. If even one read in the function is left un-scoped, it can pull in data from outside the current iteration.

My roll-up (placed outside a Content Loop) isn't finding any answers.
By default, answers() reaches across all loop iterations when called from outside the loop, but if nothing comes back, try setting the scope explicitly with { scope: Scope.global } to confirm scope isn't the issue.

My function isn't recalculating when I change an answer.
Recalculation runs on a short debounce after a dependency changes. If it still doesn't update, confirm the tag you changed is actually one the function reads — a typo in the tag name inside your code won't throw an error, it'll just silently return nothing for that read.

I'm getting a script error instead of a result.
Errors show the message and the line number where they occurred. Common causes are ES6 syntax (let, const, arrow functions, template literals) slipping in, or a runaway loop hitting the evaluation step limit — check for infinite loops like while (true) {}.