Skip to main content

Dangerous JS — Conditions

eSheet supports three condition modes for driving field visibility, enabled state, and required state. Two are safe (no JS execution); one requires the dual opt-in gate.


Condition Modes Overview​

ModeconditionTypeRequires dangerous JS?When to use
Field'field'NoDirect comparison against another field's value
Expression'expression'NoArithmetic or boolean logic across multiple fields
JS'js'YesComplex logic, date windows, arbitrary JavaScript

All three modes are evaluated inside a ConditionalRule:

effect: visible
logic: AND
conditions:
- conditionType: field
targetId: pain-level
operator: greaterThan
expected: '3'

Field Conditions (conditionType: 'field')​

Reference another field's response directly. Does not require dangerous JS.

conditionType: field
targetId: has-allergies
operator: equals
expected: 'Yes'

Available operators:

OperatorDescription
equalsValue equals expected
notEqualsValue does not equal expected
containsString contains expected substring
includesArray includes expected item
emptyValue is empty / unanswered
notEmptyValue is present / answered
greaterThanNumeric value > expected
greaterThanOrEqualNumeric value >= expected
lessThanNumeric value < expected
lessThanOrEqualNumeric value <= expected

Property accessor — use .length or .count on array responses:

conditionType: field
targetId: symptoms
operator: greaterThan
expected: '2'
propertyAccessor: count

Expression Conditions (conditionType: 'expression')​

Use eSheet's safe expression evaluator. Does not require dangerous JS.

  • Field references use {fieldId} syntax
  • Supports arithmetic (+, -, *, /, %), comparison (==, !=, <, <=, >, >=), and logical (&&, ||, !) operators
  • Supports {fieldId}.length and {fieldId}.count property accessors
  • Does not use new Function — evaluation is sandboxed by design
  • Works even when dangerous JS is disabled
conditionType: expression
expression: '{temperature} >= 38 && {symptoms}.count > 1'
conditionType: expression
expression: "{total-score} >= 8 || {override-flag} == 'Yes'"

For most business rules, expression conditions are sufficient. Use JS conditions only when the logic requires function calls, date manipulation, or external data.


JS Conditions (conditionType: 'js')​

Arbitrary JavaScript for complex conditional logic. Requires dangerouslyAllowJS: true in the schema and allowDangerousJS={true} on the host component.

Schema​

id: followup-section
fieldType: section
rules:
- effect: visible
logic: AND
conditions:
- conditionType: js
expression: responses['has-symptoms'] === 'Yes' && new Date() > new Date(responses['onset-date'])

The expression must evaluate to a truthy value for the condition to pass. If dangerouslyAllowJS is disabled, conditionType: 'js' always evaluates as false.

Expression Context​

Every JS condition receives two arguments:

responses​

A flat Record<string, unknown> — same shape as calculations:

Field typeresponses['id'] value
text / longtextNumber if parseable, otherwise raw string
radio / dropdownOption score (if set), otherwise option value string
check / multiselectdropdownArray of selected values (or scores if any are set)
rating / sliderOption score or numeric value
booleanOption value string ('Yes' / 'No' by default)
All othersRaw answer string

The internal call signature is:

new Function('responses', 'return ' + expression)(data);

Examples​

Date window — PPD read date​

Replaces legacy moment.js date range conditionals (moment(date).isBetween(...)):

conditionType: js
expression: (() => { const tested = new Date(responses['ppd-date-tested']); if (!tested || isNaN(tested)) return false; const now = new Date(); const diffDays = (now - tested) / (1000 * 60 * 60 * 24); return diffDays >= 2 && diffDays <= 8; })()

Today relative date comparisons​

Replaces legacy todayIsAfter(), todayIsBefore(), todayIsBetween(), todayIsDate():

conditionType: js
expression: new Date() > new Date('2019-06-24')
conditionType: js
expression: new Date() < new Date('2007-02-13')
conditionType: js
expression: new Date() >= new Date('2019-12-15') && new Date() <= new Date('2020-03-25')

Multi-OR: show if yes was answered to any of several fields​

Replaces legacy multi-observationDisplay OR chains:

effect: visible
logic: OR
conditions:
- conditionType: js
expression: responses['fatigue-field'] === 'Yes'
- conditionType: js
expression: responses['sleep-problems-field'] === 'Yes'
- conditionType: js
expression: responses['sleeping-aids-field'] === 'Yes'

Or equivalently with a single JS condition:

conditionType: js
expression: "['fatigue-field', 'sleep-problems-field', 'sleeping-aids-field'].some(id => responses[id] === 'Yes')"

Show if any observation is answered (not empty, not zero)​

Replaces legacy observationValueByName('name') && observationValueByName('name') !== 0:

conditionType: js
expression: responses['pain-scale'] !== '' && responses['pain-scale'] !== 0

Legacy Migration Reference​

Legacy function / patterneSheet equivalent
observationValueByName('name')responses['field-id'] (within-form field reference)
jQuery.inArray(val, arr) > -1arr.includes(val) in JS condition
miearray.inSet(val, arr)arr.includes(val) in JS condition
todayIsAfter('date')new Date() > new Date('date')
todayIsBefore('date')new Date() < new Date('date')
todayIsBetween('d1', 'd2')new Date() >= new Date('d1') && new Date() <= new Date('d2')
todayIsDate('date')new Date().toDateString() === new Date('date').toDateString()
Moment.js isBetweenNative Date arithmetic — see PPD date window example above

Builder UI​

When allowDangerousJS={true} is passed to <EsheetBuilder> and the loaded schema has dangerouslyAllowJS: true, the Logic Editor's condition row shows a JS tab alongside Field and Expression condition modes.