Have an idea?

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

Selecting images in a select question

I have two select questions (one is single response and one is multiple response).

Each question uses the same parent list which consists of 10 images.

Ideally, I would like to display the image list without radio buttons and check boxes and enable the respondent to simply click on the image and somehow display to the respondent that they have selected that image (either raise or sink the image or change the background colour - happy to see the available options).

As the respondent hovers over the image, the cursor should change to a clickable cursor. I believe Zachary's code will do this ...
<style>
.submitOnClick {
    cursor: pointer;
}
</style>

Looking for a neat answer. Appreciate any assistance.

Note: Is it possible to have a solution that works in v7-v8-v9.
asked Nov 2, 2016 by Paul Moon Platinum (62,030 points)

1 Answer

0 votes
I have accomplished this within a free format question.

For the single response option, I created "RadioFreeFormatQ" and gave it a hidden variable named "Radio."  This is the code I put in the HTML section:

<div id="ffImgContainer">
    [% Begin Unverified Perl
        my $htmlOut = '';
        my $imgDiv = '';
        for (my $i = 1; $i <= LISTLENGTH('ImgList'); $i++) {
            $htmlOut .= $imgDiv;
            $imgDiv = '<br/>';
            $htmlOut .= LISTLABEL('ImgList', $i);
        }
        return $htmlOut;
    End Unverified %]
</div>
<input name="RadioFreeFormatQ_Radio" id="RadioFreeFormatQ_Radio" type="hidden" value="">

<style>
#ffImgContainer img {
    cursor: pointer;
}

.ffSelected {
    box-shadow: 0px 12px 22px 1px #333;
}
</style>

<script>
$(document).ready(function(){
    var startVal = $('#RadioFreeFormatQ_Radio').val();
    if (startVal != '') {
        $('#ffImgContainer img:nth-of-type(' + startVal + ')').addClass('ffSelected');
    }

    $('#ffImgContainer img').each(function(){
        $(this).click(function(){
            var index = $('#ffImgContainer img').index($(this)) + 1;
            $('#RadioFreeFormatQ_Radio').val(index);
            $('#ffImgContainer img').removeClass('ffSelected');
            $(this).addClass('ffSelected');
        })
    })
})
</script>


For the multiple response option, I created "CheckFreeFormatQ" and gave it hidden variables "Check1," "Check2," ...  I used this similar code in the HTML section:

<div id="ffImgContainer">
    [% Begin Unverified Perl
        my $htmlOut = '';
        my $imgDiv = '';
        for (my $i = 1; $i <= LISTLENGTH('ImgList'); $i++) {
            $htmlOut .= $imgDiv;
            $imgDiv = '<br/>';
            $htmlOut .= LISTLABEL('ImgList', $i);
        }
        return $htmlOut;
    End Unverified %]
</div>
<input name="CheckFreeFormatQ_Check1" id="CheckFreeFormatQ_Check1" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check2" id="CheckFreeFormatQ_Check2" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check3" id="CheckFreeFormatQ_Check3" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check4" id="CheckFreeFormatQ_Check4" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check5" id="CheckFreeFormatQ_Check5" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check6" id="CheckFreeFormatQ_Check6" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check7" id="CheckFreeFormatQ_Check7" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check8" id="CheckFreeFormatQ_Check8" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check9" id="CheckFreeFormatQ_Check9" type="hidden" value="0">
<input name="CheckFreeFormatQ_Check10" id="CheckFreeFormatQ_Check10" type="hidden" value="0">

<style>
#ffImgContainer img {
    cursor: pointer;
}

.ffSelected {
    box-shadow: 0px 12px 22px 1px #333;
}
</style>

<script>
$(document).ready(function(){
    for (var i = 1; i <= 10; i++) {
        if ($('#CheckFreeFormatQ_Check' + i).val() == 1) {
            $('#ffImgContainer img:nth-of-type(' + i + ')').addClass('ffSelected');
        }
    }

    $('#ffImgContainer img').each(function(){
        $(this).click(function(){
            var index = $('#ffImgContainer img').index($(this)) + 1;
            if ($('#CheckFreeFormatQ_Check' + index).val() == 1) {
                $('#CheckFreeFormatQ_Check' + index).val(0);
                $('#ffImgContainer img:nth-of-type(' + index + ')').removeClass('ffSelected');
            }
            else {
                $('#CheckFreeFormatQ_Check' + index).val(1);
                $('#ffImgContainer img:nth-of-type(' + index + ')').addClass('ffSelected');
            }
        })
    })
})
</script>


In both codes, my question name should be replaced with yours.  In addition, "ImgList" should be replaced with the name of your list.

Currently, I highlight selected items by giving them a box shadow.  This can easily be modified by changing the ".ffSelected" part of the CSS.
answered Nov 2, 2016 by Zachary Platinum Sawtooth Software, Inc. (81,800 points)
edited Nov 2, 2016 by Zachary
Legend Mr Anderson! Prompt, generous and insightful as always.

I will give this a try later today and report back to you.

Onya mate.
Hi Zachary, I just tested the radio option.

I got it to work and I do like the box shadow effect. Nice.

Two issues I spotted ...

1/ I had the required option ticked. If I select an image or I don't  select an image, either way it does not let me proceed. When I unticked the required option, I was able to proceed to check if the data was captured correctly which it was. Is there something in the code preventing it from moving forward with the required option ticked? I do need this turned on.

2/ If I move to the next screen and then click the back button, the selected image (or the shadow box) has disappeared. Can that be resurrected?

Thanks again.
I've added a few lines to the beginning of the JS to fix problem 2.

As for problem 1, I used hidden-type variables, not radio/check-type variables.  Hidden variables don't support required responses out of the box, but custom JavaScript should be able to handle this.

This is all the single select needs:

if ($('#RadioFreeFormatQ_Radio').val() == '') {
    strErrorMessage = 'Response required.';
}


This will serve for the multiple select:

var minChecks = 1;
var maxChecks = 5;
var numChecked = 0;
for (var i = 1; i <= 10; i++) {
    if ($('#CheckFreeFormatQ_Check' + i).val() == 1) {
        numChecked++;
    }
}

if (numChecked < minChecks) {
    strErrorMessage = 'Too few selected.';
}
if (numChecked > maxChecks) {
    strErrorMessage = 'Too many selected.';
}


Lines 1 and 2 can be updated with the minimum and maximum selections.
Thanks Zachary. Problem 1 is now working for the radio option. I unticked the required box and implemented the JavaScript and all good.

I copied your new script for the HTML window but it doesn't appear to work as expected. If I backup, the shadow box does not appear on the selected image and if I try to go forward again, it says I have not responded to the question. So it looks like backing up needs to not wipe the response and show the shadow box.
You need to change the "Variable Type" dropdown from "radio" to "hidden."  There shouldn't a "Require response" checkbox available.
Aaahh, got it! Thanks mate for pointing me in the right direction.

I will test the multiple response option later today and get back to you.

Thanks heaps mate.
Validation for a mutually exclusive option
...