Forum Discussion

ronald-hicks's avatar
ronald-hicks
Community Member
1 day ago

Prime your result variable before every JS check — the "evaluate" sentinel trick

Ran into a wrong-branch bug on a test-out interaction recently and wanted to share the fix, because the failure mode is sneaky.

 

The setup: a slide runs a JavaScript check (e.g., "has this learner already passed this module?") and stores the result in a variable. Triggers then branch on that variable. Works fine the first time through. But when the learner revisits the slide — or resumes the course from the LMS later — the variable still holds the *previous* attempt's value, and the branch triggers can fire on stale data before the new check runs. Wrong branch, confused learner, and you only catch it in testing if you actually revisit.

 

The fix is small: prime the variable to a sentinel value at the start of every attempt, *before* the check runs.

 

Literal steps:

 

1. Create a Text variable, e.g. testOutResult.

2. On the decision slide, add these triggers in this exact order, on the same event ("when timeline starts" works):

   a. Set testOutResult = evaluate

   b. Execute JavaScript — your check, which ends by setting testOutResult to its real result (pass / fail / whatever your outcomes are)

   c. Jump to slide … when testOutResult == pass

   d. Jump to slide … when testOutResult == fail

   e. (Safety net) Jump to a default slide when testOutResult == evaluate

3. Done.

 

Why it works: Storyline fires triggers on the same event in panel order, and an Execute JavaScript trigger runs synchronously — so by the time the branch triggers evaluate, the variable holds the fresh result. On revisit, the prime step wipes the stale value first. And if the check itself errors out, the variable is still sitting at "evaluate" when the branch triggers evaluate, so the safety-net trigger (e) catches it instead of a branch firing on garbage. Fail closed, not fail wrong.

 

Four things to get right:

 

- The sentinel must be a value the check can never produce. If your outcomes are pass/fail, "evaluate" is safe. Keep it visually distinct so future-you doesn't collide with it.

- Branch on positive equality only. Never "when variable changes, if testOutResult != pass" — the priming step itself changes the variable, and a negative condition would fire at prime time. Use == on each real outcome, nothing else.

- Synchronous JS only. If the check uses await, fetch, or timers, the branch triggers evaluate before the result lands and no sentinel can save you. Restructure so the result is set synchronously.

- The LMS resume is where this pays for itself. Preview and published output behave the same for trigger ordering — but only the LMS restores variable values from suspend data across sessions. A stale "pass" surviving a resume is exactly the bug the sentinel makes visible. Test the revisit path in the LMS, not just in preview.

 

I use this anywhere a JS check feeds a jump: test-outs, resume routing, feature flags. Costs one extra trigger.

 

---

Footnote: I keep a few of my reusable Storyline JS bits in a free sampler here: https://ronaldhicks.gumroad.com/l/storyline-js-sampler

No RepliesBe the first to reply