Have an idea?

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

Stars Rating Grid with 'Don't know'

Hello everyone,

is it possible to add a 'Don't know'-Option to each row of the Stars Rating Grid (https://www.sawtoothsoftware.com/community-question-library/1780-stars-rating)?

Best regards,
Kathrin
asked Feb 26 by Kathrin

1 Answer

0 votes
If you haven't already, start by getting "Not Applicable: Per Variable" from the Community Question Library and replace its footer with this modified script:

<style>
#[% QuestionName() %]_div {
    display: none;
}

.error_quest_highlight2 {
    border: 1px solid red !important;
}
</style>

<script>
var GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS = {
    questionName: '',
    notApplicableLabel: 'N/A',
    checkboxMinimumChecks: 0, // If the question uses checkboxes, this can be updated with the minimum number of checks a respondent must respond with.
    errorMessage: 'Question must be answered or "Not Applicable" must be selected.'
};

$(document).ready(function(){
    // Icons
    var icons = {
        empty: 'fa-star',
        half: 'fa-star-half',
        full: 'fa-star'
    };

    // Question, list
    if (!GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.questionName) {
        GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.questionName = $('#[% QuestionName() %]_div').prevAll('.question')[0].id.replace(/_div/, '');
    }
    var question = GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.questionName;
    var qdiv = $('#' + question + '_div');
    var list = $('input[name=hid_list_[% QuestionName() %]]').val().split(',').map(Number);

    // Move checkboxes
    $('#[% QuestionName() %]_div .mobile_select').removeClass('mobile_select');
    $('#[% QuestionName() %]_div .response_row').css('text-align', 'center');
    $('#[% QuestionName() %]_div .input_cell').css('display', 'inline-block');
    $('#[% QuestionName() %]_div .option_cell').css('display', 'inline-block');
    
    GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.grid = SSI_GetGridQuestionSettings(question);
    
    if (!GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.grid.mobile) {
        $('#[% QuestionName() %]_div .option_cell').remove();
        if (GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.grid.orientation == 'row') {
            $('#' + question + '_div .column_header_row').append('<td>' + GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.notApplicableLabel + '</td>');
            $('#' + question + '_div .inner_table > tbody > tr:first-child > td:last-child').css('text-align', 'center');
            list.forEach(function(item){
                $('#' + question + '_r' + item + '_row').append('<td></td>');
                $('#' + question + '_r' + item + '_row > td:last-child').append($('#[% QuestionName() %]_' + item).closest('.response_row'));
            });
        }
        else {
            $('#' + question + '_div .inner_table > tbody').append('<tr><td>' + GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.notApplicableLabel +'</td></tr>');
            $('#' + question + '_div .inner_table > tbody > tr:last-child > td').css('text-align', 'right');
            list.forEach(function(item){
                $('#' + question + '_div .inner_table > tbody > tr:last-child').append('<td></td');
                $('#' + question + '_div .inner_table > tbody > tr:last-child > td:last-child').append($('#[% QuestionName() %]_' + item).closest('.response_row'));
            });
        }
        fixGridAltColors(question);
    }
    
    else {
        $('#[% QuestionName() %]_div .option_cell label').text(GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.notApplicableLabel);
        list.forEach(function(item){
            $('#' + question + '_div .mobile_grid_card[data-card_num=' + item + ']').append($('#[% QuestionName() %]_' + item).closest('.response_row'));
        });
    }

    // N/A click event
    var runNotApplicable = function(){
        var columns = $('input[name="hid_col_list_' + question + '"]').val().split(',');
        list.forEach(function(item){
            if (SSI_GetValue('[% QuestionName() %]_' + item)) {
                var input = $('#' + question + '_r' + item + '_c' + columns[0]);
                $(input).val('');
                updateStars(question, item, 0, icons);
                var starsContainer = $(input).siblings('.starsContainer');
                $(starsContainer).css('position', 'relative');
                $(starsContainer).find('.star').css('opacity', .5);
                var overlay = $('<div class="starOverlay"></div>');
                $(overlay).css('position', 'absolute').css('top', 0).css('left', 0).css('height', '100%').css('width', '100%').css('z-index', 9999);
                $(overlay).click(function(e){
                    e.stopPropagation();
                });
                $(starsContainer).append($(overlay));
            }
            else {
                var starsContainer = $('#' + question + '_r' + item + '_c' + columns[0]).siblings('.starsContainer');
                $(starsContainer).find('.star').css('opacity', 1);
                $(starsContainer).find('.starOverlay').remove();
            }
        });
    }
    
    $(document).on('lighthouseCheckboxChanged', runNotApplicable);
    runNotApplicable();
})

function fixGridAltColors(question) {
    if (!$('#' + question + '_div .mobile_grid').length) {
        var firstCellIsAltColor1 = $('#' + question + '_div .inner_table > tbody > tr:first-child > td:nth-child(1)').hasClass('alt_color1');
        var secondCellIsAltColor1 = $('#' + question + '_div .inner_table > tbody > tr:first-child > td:nth-child(1)').hasClass('alt_color1');
        var primaryAltColor = firstCellIsAltColor1 ? 'alt_color1' : 'alt_color2';
        var secondaryAltColor = firstCellIsAltColor1 ? 'alt_color2' : 'alt_color1';
        
        if (firstCellIsAltColor1 == secondCellIsAltColor1) {
            $('#' + question + '_div .inner_table > tbody > tr:even > td').removeClass(secondaryAltColor).addClass(primaryAltColor);
            $('#' + question + '_div .inner_table > tbody > tr:odd > td').removeClass(primaryAltColor).addClass(secondaryAltColor);
        }
        
        else {
            $('#' + question + '_div .inner_table > tbody > tr > td:even').removeClass(secondaryAltColor).addClass(primaryAltColor);
            $('#' + question + '_div .inner_table > tbody > tr > td:odd').removeClass(primaryAltColor).addClass(secondaryAltColor);
        }
    }
}
</script>


Lines 22-24 should be updated with icon information in the stars question.

Note that this question also requires "Better Lighthouse Library" from the Community Question Library as well.
answered Feb 26 by Zachary Platinum Sawtooth Software, Inc. (144,125 points)
Hi Zarachy,

thank you for your reply. I managed to add the don't know option, but now the next- button doesn't work. I suspect there's an error in the custom javascript verification and I don't know how to solve it.

My set-up is as follows:
CX01 is the grid variable with 6 Items( I made sure that the rows  don't require a response)
CX01kA is the "Not Applicable: Per Variable" -  I added 6 Response options, one per item of the grid
and I added the BetterLighthouseLibrary, all on the same page.

The error:
Uncaught ReferenceError: GLOBAL_SAWTOOTH_CX01kA is not defined
    at SSI_CustomJScriptShell_CX01kA (ciwweb.pl:159)
    at SSI_Verify (ciwweb.pl:1511)
    at SSI_SubmitMe (ssi_javascript9_8_0.js:80)
    at SSI_NextSubmit (ssi_javascript9_8_0.js:651)
    at HTMLDivElement.<anonymous> (ssi_javascript9_8_0.js:479)
    at HTMLDivElement.dispatch (jquery-3.2.1.min.js:3)
    at HTMLDivElement.q.handle (jquery-3.2.1.min.js:3)

The error seems to be in this row:
// Row-oriented grid
        else if ($(qdiv).hasClass('grid') && GLOBAL_SAWTOOTH_[% QuestionName() %].gridOrientation == 'r') {
            var cols = $('input[name=hid_col_list_' + question + ']').val().split(',').map(Number);

Any help is much appreciated!
Kathrin
First off, thanks for getting me the error from the console and the line of code that threw the error.  It's super helpful.

I updated "Not Applicable: Per Variable" earlier this month.  I think your custom JavaScript verification is from the older version of the code, while my modified footer code has the new version of the code in mind.  This is the custom JavaScript verification I'm using:

var question = GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.questionName;
var qdiv = $('#' + question + '_div');
var list = $('input[name=hid_list_[% QuestionName() %]]').val().split(',').map(Number);
var minimumChecks = GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks;
var grid = GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.grid;
var err;

for (var i = 0; i < list.length && !err; i++) {
    var item = list[i];
    if (!SSI_GetValue('[% QuestionName() %]_' + item)) {
        // Semantic diff
        if ($(qdiv).hasClass('semanticdiff')) {
            err = !SSI_GetValue(question + '_' + item);
        }

        // Row-oriented grid
        else if (GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.grid.orientation == 'row') {
            var columns = grid.columns;
            var constantSumOrRanking = grid.variables[i].variableType == 'constant sum' || grid.variables[i].variableType == 'ranking';
            
            // Radio
            if ($('#' + question + '_r' + item + '_' + columns[0] + '[type=radio]').length) {
                err = !SSI_GetValue(question + '_r' + item);
            }

            // Check
            else if ($('#' + question + '_r' + item + '_c' + columns[0] + '[type=checkbox]').length) {
                var checks = 0;
                $(qdiv).find('input[type=checkbox][id^=' + question + '_r' + item + '_]').each(function(){
                    checks += SSI_GetValue(this.id);
                });
                err = checks < minimumChecks;
            }

            // Combo
            else if ($('select#' + question + '_r' + item + '_c' + columns[0]).length && !constantSumOrRanking) {
                for (var c = 0; c < columns.length && !err; c++) {
                    err = !SSI_GetValue(question + '_r' + item + '_c' + columns[c]);
                }
            }

            // Open end, numeric
            else if (!constantSumOrRanking) {
                for (var c = 0; c < columns.length && !err; c++) {
                    err = !$('#' + question + '_r' + item + '_c' + columns[c]).val().length;
                }
            }

            // Combo ranking
            else if ($('select#' + question + '_r' + item + '_c' + columns[0]).length) {
                err = true;
                for (var c = 0; c < columns.length && err; c++) {
                    err = !SSI_GetValue(question + '_r' + item + '_c' + columns[c]);
                }
            }

            // Constant sum, tel ranking
            else {
                err = true;
                for (var c = 0; c < columns.length && err; c++) {
                    err = !$('#' + question + '_r' + item + '_c' + columns[c]).val().length;
                }
            }
        }

        // Col-oriented grid
        else {
            var rows = grid.rows;
            var constantSumOrRanking = grid.variables[i].variableType == 'constant sum' || grid.variables[i].variableType == 'ranking';
            
            // Radio
            if ($('#' + question + '_c' + item + '_' + rows[0] + '[type=radio]').length) {
                err = !SSI_GetValue(question + '_c' + item);
            }

            // Check
            else if ($('#' + question + '_r' + rows[0] + '_c' + item + '[type=checkbox]').length) {
                var checks = 0;
                $(qdiv).find('input[type=checkbox][id^=' + question + '_][id$=_c' + item + ']').each(function(){
                    checks += SSI_GetValue(this.id);
                });
                err = checks < minimumChecks;
            }

            // Combo
            else if ($('select#' + question + '_r' + rows[0] + '_c' + item).length && !constantSumOrRanking) {
                for (var r = 0; r < rows.length && !err; r++) {
                    err = !SSI_GetValue(question + '_r' + rows[r] + '_c' + item);
                }
            }

            // Open end, numeric
            else if (!constantSumOrRanking) {
                for (var r = 0; r < rows.length && !err; r++) {
                    err = !$('#' + question + '_r' + rows[r] + '_c' + item).val().length;
                }
            }

            // Combo ranking
            else if ($('select#' + question + '_r' + rows[0] + '_c' + item).length) {
                err = true;
                for (var r = 0; r < rows.length && err; r++) {
                    err = !SSI_GetValue(question + '_r' + rows[r] + '_c' + item);
                }
            }

            // Constant sum, tel ranking
            else {
                err = true;
                for (var r = 0; r < rows.length && err; r++) {
                    err = !$('#' + question + '_r' + rows[r] + '_c' + item).val().length;
                }
            }
        }
    }
}

// Error
$(qdiv).removeClass('error_quest_highlight2');
$('#' + question + '_err2').remove();

if (err) {
    strErrorMessage = GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.errorMessage;

    $(qdiv).removeClass('error_quest_highlight');
    $('#' + question + '_err').remove();
    $(qdiv).addClass('error_quest_highlight2');
    $(qdiv).prepend('<div id="' + question + '_err2" class="question_error_box error_messages"></div>');
    $('#' + question + '_err2').append('<div class="question_errors">' + strErrorMessage + '</div>');
}
...