Have an idea?

Visit Sawtooth Software Feedback to share your ideas on how we can improve our products.

Javascript Verification for a Loop

I have a question regarding modes of transportation, struggling with a solution.  I have a question asking respondents to click all types of transportation they would take in a typical commute, with 22 options, select all that apply.  From there, they will be asked to list the order in which they use these items (assuming they chose more than one option).

To do this, I first ask what the first option was, with a constructed list showing the options they chose.  From there, they go into a loop showing each of the options as well as the additional "That is the end of my trip", which drops them out of the loop.  I don't want to remove the options as they are chosen, because if someone uses a mode of transportation twice (e.g. walk to the train station, take the train, walk to the office) they'll need to choose that item twice.  

My issue is I want to make sure they don't jump out of the loop early by selecting  "That is the end of my trip" without using all of the items they chose at least once.  My initial thought was a javascript verification to make sure that at least the lists of what they see and what they chose are the same, but it would be much more useful to compare the list chosen from the loop to the original list to make sure each list contains the same items.  

Thanks in advance for any help provided.
asked Dec 15, 2020 by Geoff Yeaton
The looped question is a single-select question, right?  With one item from each of the 22 options that was selected + one item to break out of the loop?
Zachary, indeed it is.  Single-select drop-down, with the one item that breaks them out.

1 Answer

0 votes
I think I've got it.  Please try setting the custom JavaScript verification of your looped question to this:

[% Begin Unverified Perl
# Params
my $firstQ = 'Q1';
my $loop = 'loop1';
my $itemCount = 22;

# Run
my $output = 'var noneItem = ' . ($itemCount + 1) . ';';

my %remaining = ();
for (my $i = 1; $i <= $itemCount; $i++) {
    if (GETVALUE($firstQ . '_' . $i)) {
        $remaining{$i} = 1;

my $allUsed = 0;
my $loopMax = LOOPITERATION($loop);
for (my $i = 1; $i < $loopMax; $i++) {
    delete $remaining{GETVALUE(QUESTIONNAME() . '.' . $i)};
    if (!scalar(keys(%remaining))) {
        $allUsed = 1;
$output .= 'var allUsed = ' . ($allUsed ? 'true' : 'false') . ';';

return $output;
End Unverified %]

if (!allUsed && SSI_GetValue('[% QuestionName() %]') == noneItem) {
    strErrorMessage = 'error message...';

Line 3 should be updated with the name of the select question that comes before this looped question.  Line 4 should be updated with the name of the loop.
answered Dec 15, 2020 by Zachary Platinum Sawtooth Software, Inc. (171,950 points)
Should "Q1" in the above question reference the multi-select question where they choose all transportation types or the first option?  Here's how the sequence goes:

q152 - Multi-choice select showing 22 transport types
q153a - First choice (drop down of selections from q152)
[Begin Loop]
q153b - Next choice (drop down of selections from q152 with added "That is the end of my trip")

It seems to be requiring one or two extra choices before it allows the skip-out.  If it helps, I can remove q153a and just make that part of the loop , showing either First Choice or Next Choice depending on Loop Value.
Yeah, I was imagining q153 being a single question rather than split into a first question and a second looped question.  The "Q1" was intended to be q152.
Zachary, I updated the loop to include the first mode and it looks like it's working perfectly so far!  Thanks so much for this solution!!