Have an idea?

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

CBC Randomization by variable

I have a CBC exercise, and I’d like to use an order for the attribute display that matches the order stored in a variable (passed from Cmix).  Is there a way to do that?  The variable would be ORDER, and it would look like 1,5,4,3,8,2,7,6,9  - where I’m locking the first and last attributes and randomizing the middle.  I’d like the CBC to match what order I have in Cmix though, and not use the randomization within Sawtooth.  Is this possible?
asked Jan 11 by Kristen
Certainly.  What version of Lighthouse Studio / SSI Web are you running?
9.14.2  Thank you for your help!  I don't know Perl, if that's the solution, so as much step-by-step you can provide would be helpful.

1 Answer

0 votes
No Perl today.  Please try adding this script to your CBC:

<script>
$(document).ready(function(){
    // Settings
    var list = [[% MyVar %]];
     
    // Run
    $('#[% QuestionName() %]_div .cbc_task > :not(.none_concept)').each(function(){
        for (var i = list.length - 1; i >= 0; i--) {
            var attribute = list[i];
            $(this).prepend($(this).find('.att_' + attribute));
        }
        $(this).find('.first_att').removeClass('first_att');
        $(this).children().eq(0).addClass('first_att');
    });
})
</script>


"MyVar" should be replaced with the name of the survey variable with the attribute order.
answered Jan 11 by Zachary Platinum Sawtooth Software, Inc. (214,575 points)
This works!  Thank you!!!! The only issue I saw was that it moves the Concept Labels from the top, to above the input.  Is there a way to keep the labels at the top?
You're welcome.  Here's a modified version meant to work with concept labels:

<script>
$(document).ready(function(){
    // Settings
    var list = [[% var %]];
     
    // Run
    $('#[% QuestionName() %]_div .cbc_task > :not(.none_concept)').each(function(){
        for (var i = list.length - 1; i >= 0; i--) {
            var attribute = list[i];
            $(this).children().eq(0).after($(this).find('.att_' + attribute));
        }
        $(this).find('.first_att').removeClass('first_att');
        $(this).children().eq(1).addClass('first_att');
    });
})
</script>
Hi Zachary,

Thanks again!  Looks great on desktop, but the display on mobile isn't working correctly.  The attributes/levels aren't being displayed within the concept container - they're below.  So it's showing the toggle at the top, the container (with only the selection button), the attribute/level detail, then the dual response option.  Is this something you can help with?  Thanks so much!
I'm not able to reproduce that on my machine.  You mentioned dual response, but I tried both making my CBC best-worst and setting the none option to dual response, but still didn't see anything.  Is there more I need to do to get my CBC like yours?
Hmm, my other settings are:

-Show attribute labels (left of concept)
-Swipe concepts horizontally
-Show concept labels (but not repeated above input)

I wouldn't have thought that this would have impacted the display, but maybe the code below?  This is something that someone else wrote for me to force respondents on mobile to view all concepts before they can answer.  Would this mess with the mobile display?

<script>
$(document).on('ssi_ready', function(){
    // Disable
    var buttons = $('#[% QuestionName() %]_div .task_select_button, #[% QuestionName() %]_div .dual_response_none_button');
    var inputs = $('#[% QuestionName() %]_div .numeric_input');
     
    $(buttons).each(function(){
        var clone = $(this).clone();
        $(clone).addClass('cbcCloneButton');
        $(clone).find('.input_cell').remove();
        $(this).after(clone);
        $(this).hide();
    });
    $(inputs).prop('disabled', true);
     
    // Enable
    var isEnabled = false;
    var enable = function() {
        if (!isEnabled) {
            isEnabled = true;
            $(buttons).each(function(){
                $(this).next().remove();
                $(this).show();
            });
            $(inputs).prop('disabled', false);
        }
    };
     
    var answered = $('#[% QuestionName() %]_div .cbc_task.discrete').length && SSI_GetValue('[% QuestionName() %]');
    answered ||= $('#[% QuestionName() %]_div .cbc_task.best_worst').length && SSI_GetValue('[% QuestionName() %]_b');
    answered ||= $('#[% QuestionName() %]_div .cbc_task.constant_sum').length && Number($('#[% QuestionName() %]_total').val());
    if (answered) {
        enable();
    }
     
    $(window).resize(function(){
        if (!$('#[% QuestionName() %]_div .owl-loaded').length) {
            enable();
        }
    });
    $(window).resize();
     
    $('#[% QuestionName() %]_div .owl-item.center').addClass('viewed');
    $('#[% QuestionName() %]_div .owl-carousel').on('changed.owl.carousel', function(){
        var interval = setInterval(function(){
            $('#[% QuestionName() %]_div .owl-item.center').addClass('viewed');
            if (!$('#[% QuestionName() %]_div .owl-item:not(.viewed)').length) {
                enable();
            }
            clearInterval(interval);
        }, 100);
    });
})
</script>
I'm still not seeing anything.  Would it be possible for you to share your .ssi with support@sawtoothsoftware.com so I can see your full study?
Whoops, looks like that CSS selector could have been better.  Try this:

<script>
$(document).ready(function(){
    // Settings
    var list = [[% ORDER %]];
      
    // Run
    $('#[% QuestionName() %]_div .attribute_label_column, #[% QuestionName() %]_div .cbc_concept:not(.none_concept)').each(function(){
        for (var i = list.length - 1; i >= 0; i--) {
            var attribute = list[i];
            $(this).children().eq(0).after($(this).find('.att_' + attribute));
        }
        $(this).find('.first_att').removeClass('first_att');
        $(this).children().eq(1).addClass('first_att');
    });
})
</script>
...