Logic Guide
JavaScript logic runs only in controlled DSL locations. The same safe evaluator is shared by Survey Link, Workbench preview, Run generate, server persistence, Template Expressions, and redirect route evaluation.
| Location | Purpose | Mutation |
|---|---|---|
if | Compact visibility or inclusion expression for questions, options, attributes, groups, screen-outs, quotas, jumps, and redirect routes. | No |
<condition> | Multi-line boolean condition with a top-level final return. | No |
<run-code> | Flow-time answer mutation, auto-punching, and diagnostics. | Yes, through setAnswer, clearAnswer, and question-object mutation methods |
<validation> | Question-local hard or soft validation. | No answer mutation |
<script> helper | Reusable safe predicates or transforms. | No answer mutation |
{{ ... }} Template Expression | Render-time text, dynamic non-identity attributes, and redirect route URLs. | No |
Runtime helper availability
| Helper | Type | Available in | Notes |
|---|---|---|---|
Luxon | Namespace with DateTime, Duration, Interval | All JS DSL and Template Expression contexts that use the default survey logic context. | Use for deterministic date parsing and formatting. |
$now | Current Luxon DateTime | if, <condition>, <run-code>, <validation>, Template Expressions, redirect route if, and redirect URL templates. | $now is evaluated at runtime, not at save time. |
$params | Survey Link URL parameter object | Survey Link runtime, server persistence, redirect route if, redirect URL templates, Template Expressions, and Run generate when a runtime context supplies params. | System keys such as mode, isTestMode, vs-sys-*, and redirectGroup are reserved and not exposed. Duplicate params are exposed as string arrays. |
$curr | Current question object | Question-local if, <condition>, <run-code>, <validation>, option if, attribute if, and option/attribute group if. | It points to the question currently being evaluated. It is intentionally not available in top-level share-list, screen-out, quota, jump, or redirect scopes. |
$quota | Read-only quota snapshot namespace | if, <condition>, <run-code>, <validation>, screen-out, quota, script-helper runtime contexts, Survey Link server persistence, and Run generate when quota rules are supplied. | Exposes saved quota cells and current respondent assignment without direct database access. |
$status | Redirect terminal status object | Redirect route if only. | Provides $status.complete, $status.screenout, and $status.quotafull. |
Question references and $curr
Use named question objects when logic depends on another question, and use $curr when the logic belongs to the question currently being evaluated.
<question type="single" name="Q1">
<run-code>
if ($curr.o1 && $now.year >= 2026) {
setAnswer("SEGMENT", "qualified");
}
</run-code>
<options>
<option value="1">Qualified</option>
<option value="2" if="$curr.o1">Shown only after option 1</option>
</options>
</question>
<question type="text" name="FOLLOWUP" if="SEGMENT.value === 'qualified'">
<description>Follow-up for the qualified segment.</description>
</question>
$curr is question-scoped. In the example above, $curr.o1 means Q1.o1 while the runtime is processing Q1. A later question should reference Q1.o1 or the auto-punched SEGMENT answer explicitly.
$params and Template Expressions
URL parameters are available through $params after Survey Link sanitizes reserved system keys.
<question type="text" name="SOURCE_LABEL" hidden>
<run-code>setAnswer("SOURCE_LABEL", String($params.source || "direct"));</run-code>
</question>
<question type="info" name="INTRO">
<description>Welcome, {{ $params.company || "respondent" }}.</description>
</question>
Template Expressions are read-only. They can read answers, helpers, Luxon, $now, and the runtime-provided $params object, but they cannot mutate answers.
Script helpers in expressions
Survey HTML DSL <script> blocks can expose restricted top-level functions to if expressions, Template Expressions, <condition>, <run-code>, and <validation>. The helper body must pass the safe helper sandbox.
<script name="helpers">
function answerConvert(value) {
return String(value || "").trim().toUpperCase();
}
</script>
<question type="single" name="FOLLOWUP" if="answerConvert(Q1.val()) === 'YES'">
<description>{{ answerConvert(Q1.val()) }} path follow-up</description>
</question>
Keep helper code pure. Use <run-code> for answer mutation.
$quota helper
$quota is a dynamic read-only namespace keyed by quota sheet/source id. It reflects the persisted quota snapshot at the moment logic runs. It never exposes a service-role database client to authored code.
$quota.gender_quota.cells
$quota.gender_quota.get("r1")
$quota.gender_quota.getPriorityCells(1, "count")
$quota.gender_quota.getAssignmentCells()
Use it in <run-code> to auto-punch a hidden question after a quota checkpoint:
<quota source="concept_quota" />
<question type="single" name="HQ_CONCEPT" hidden>
<run-code>
const ids = $quota.concept_quota.getAssignmentCells();
const first = ids.at(0);
if (first) {
setAnswer("HQ_CONCEPT", String(first).replace("r", ""));
}
</run-code>
<options>
<option value="1">Concept A</option>
<option value="2">Concept B</option>
</options>
</question>
See Question Objects for the method contract.
Redirect route logic
Redirect route conditions use the same expression evaluator as question visibility plus the redirect-only $status helper. Routes run in source order and the first true route wins. Route URL Template Expressions can read final answers, $params, $now, and safe helpers, but the final URL must be absolute http or https.
<redirect>
<group name="partner" title="Partner" default>
<route url="https://example.com/done?source={{ $params.source }}&year={{ $now.year }}" if="$status.complete && Q1.o1" />
<route url="https://example.com/full" if="$status.quotafull" />
</group>
</redirect>
Redirect errors are blocking by design: invalid group selection, duplicate route conditions, unsafe final URLs, or redirect Template Expression failures prevent response persistence instead of saving ambiguous data.
Runtime error policy
- Save-time validation catches unsupported syntax and unsafe references before persistence.
- Runtime condition failures fail open where possible so respondents do not lose unrelated questions.
- Redirect errors are the exception: terminal redirect errors block progression and persistence.
- Run-code and validation errors are caught and reported through TEST diagnostics and runtime console events.
- Run generate uses the same helper surface and deduplicates repeated expression/runtime diagnostics.