Have an idea?

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

Only one answer required in grid with not applicable option

Hello everyone,

i have a grid question with 11 rows with numeric question type and the not applicable (per question) option.

If the not applicable option is unchecked, the respondents have to answer each row of the grid question. I would like them to only have to answer at least one row. The other rows may be empty.

I am not so good with java script, so i would be very happy about some help.

Best regards,
Eva
asked Aug 10, 2021 by Eva

1 Answer

0 votes
The simplest workaround for this would be to perform a search for this in the Not Applicable's custom verification:

var constantSumOrRanking = grid.variables[r].variableType == 'constant sum' || grid.variables[r].variableType == 'ranking';


Replace that with this:

var constantSumOrRanking = true;
answered Aug 10, 2021 by Zachary Platinum Sawtooth Software, Inc. (206,100 points)
Thank you for the fast reply! Unfortunately this does not work. I still have to answer every single row of the grid question.
Can you post your modified custom verification?
 var question = GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.questionName;
var qdiv = $('#' + question + '_div');
var err;

var notApplicable = false;
var notApplicableItems = $('input[name="hid_list_[% QuestionName() %]"]').val().split(',');
for (var i = 0; i < notApplicableItems.length; i++) {
    if (SSI_GetValue('[% QuestionName() %]_' + notApplicableItems[i])) {
        notApplicable = true;
        break;
    }
}

// Clear error
$(qdiv).find('.error_quest_highlight2').addBack().removeClass('error_quest_highlight2');
$('#' + question + '_err2').remove();

// Not applicable error
if (!notApplicable) {
    // Select
    if ($(qdiv).hasClass('select')) {
        var checkboxInputs = $(qdiv).find('input[type=checkbox][id^=' + question + '_]');
        if (!$(checkboxInputs).length) {
            err = !SSI_GetValue(question);
        }
        else {
            var checks = 0;
            $(checkboxInputs).each(function(){
                checks += SSI_GetValue(this.id);
            });
            err = checks < GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks;
        }
    }
    
    // Numeric, open end
    else if ($(qdiv).hasClass('numeric') || $(qdiv).hasClass('openend')) {
        err = !$('#' + question).val().length;
    }
    
    // Non-tel ranking
    else if ($(qdiv).hasClass('ranking') && ($(qdiv).find('select').length || $(qdiv).find('.ui-sortable').length)) {
        var list = $('input[name=hid_list_' + question + ']').val().split(',').map(Number);
        err = true;
        for (var i = 0; i < list.length; i++) {
            if (SSI_GetValue(question + '_' + list[i])) {
                err = false;
                break;
            }
        }
    }
    
    // Sem diff
    else if ($(qdiv).hasClass('semanticdiff')) {
        var list = $('input[name=hid_list_' + question + ']').val().split(',').map(Number);
        err = false;
        for (var i = 0; i < list.length; i++) {
            if (!SSI_GetValue(question + '_' + list[i])) {
                err = true;
                break;
            }
        }
    }
    
    // Constant sum, tel ranking
    else if ($(qdiv).hasClass('constantsum') || $(qdiv).hasClass('ranking')) {
        var list = $('input[name=hid_list_' + question + ']').val().split(',').map(Number);
        err = true;
        for (var i = 0; i < list.length; i++) {
            if ($('#' + question + '_' + list[i]).val().length) {
                err = false;
                break;
            }
        }
    }
    
    // Grid
    else if ($(qdiv).hasClass('grid')) {
        var grid = SSI_GetGridQuestionSettings(question);
        var rows = grid.rows;
        var cols = grid.columns;
        
        // Row-oriented
        if (grid.orientation == 'row') {
            var firstCol = cols[0];
            for (var r = 0; r < rows.length && !err; r++) {
                var row = rows[r];
                var constantSumOrRanking = true;

                // Radio
                if ($('#' + question + '_r' + row + '_' + firstCol + '[type=radio]').length) {
                    err = !SSI_GetValue(question + '_r' + row);
                }

                // Check
                else if ($('#' + question + '_r' + row + '_c' + firstCol + '[type=checkbox]').length) {
                    if (GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks) {
                        var checks = 0;
                        $(qdiv).find('input[type=checkbox][id^=' + question + '_r' + row + '_]').each(function(){
                            checks += SSI_GetValue(this.id);
                        });
                        err = checks < GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks;
                    }
                }

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

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

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

                // Constant sum, tel ranking
                else {
                    err = true;
                    for (var c = 0; c < cols.length && err; c++) {
                        var col = cols[c];
                        err = !$('#' + question + '_r' + row + '_c' + col).val().length;
                    }
                }
            }
        }
        
        // Col-oriented
        else {
            var firstRow = rows[0];
            for (var c = 0; c < cols.length && !err; c++) {
                var col = cols[c];
                var constantSumOrRanking = grid.variables[c].variableType == 'constant sum' || grid.variables[c].variableType == 'ranking';

                // Radio
                if ($('#' + question + '_c' + col + '_' + firstRow + '[type=radio]').length) {
                    err = !SSI_GetValue(question + '_c' + col);
                }

                // Check
                else if ($('#' + question + '_r' + firstRow + '_c' + col + '[type=checkbox]').length) {
                    if (GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks) {
                        var checks = 0;
                        $(qdiv).find('input[type=checkbox][id^=' + question + '_][id$=_c' + col + ']').each(function(){
                            checks += SSI_GetValue(this.id);
                        });
                        err = checks < GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks;
                    }
                }

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

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

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

                // Constant sum, tel ranking
                else {
                    err = true;
                    for (var r = 0; r < rows.length && err; r++) {
                        var row = rows[r];
                        err = !$('#' + question + '_r' + row + '_c' + col).val().length;
                    }
                }
            }
        }
    } 
     // Free format
    else if ($(qdiv).hasClass('freeformat')) {
        var freeFormat = SSI_GetFreeFormatQuestionSettings(question);
        freeFormat.variables.forEach(function(variable){
            switch (variable.variableType) {
                case 'radio':
                case 'select':
                    err = err || !SSI_GetValue(question + '_' + variable.name);
                    break;
                case 'checkbox':
                    var checks = 0;
                    if (!err || GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks) {
                        $(qdiv).find('input[id^=' + question + '_' + variable.name + '_]').each(function(){
                            if (SSI_GetValue(this.id)) {
                                checks++;
                            }
                        });
                        err = checks < GLOBAL_SAWTOOTH_[% QuestionName() %]_SETTINGS.checkboxMinimumChecks;
                    }
                    break;
                case 'numeric':
                case 'text':
                    err = err || !$('#' + question + '_' + variable.name).val().trim();
                    break;
            }
        });
    }
}

else {
    $(qdiv).find('.disabled_draggable_button input').val(''); // Hack for Sort Vertically / Sort Horizontally ranking questions
}

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

// Other specify error
for (var i = 0; i < notApplicableItems.length && !err; i++) {
    var item = notApplicableItems[i];
    if (SSI_GetValue('[% QuestionName() %]_' + item)) {
        var otherSpecifySettings = $('input[name="hid_[% QuestionName() %]_' + item + '_other"]').val();
        if (otherSpecifySettings) {
            var match = otherSpecifySettings.match(/^(\d+),(\d+),(.*)$/);
            var min = Number(match[1]);
            var max = Number(match[2]);
            var errorText = match[3];
            
            var otherSpecify = $('#[% QuestionName() %]_' + item + '_other');
            var len = $(otherSpecify).val().trim().length;
            var error;
            if (len < min) {
                error = len ? 'minimumCharacters' : 'missingAnswer';
            }
            else if (len > max) {
                error = 'maximumCharacters';
            }
            if (error) {
                err = SSI_GetStudySettings().errorMessages[error];
                var createRegex = function(func){
                    return new RegExp('\\[' + '%' + func + '\\(\\)%\\]', 'g');
                };
                err = err.replace(createRegex('ERRTEXT'), errorText).replace(createRegex('ERRMIN'), min).replace(createRegex('ERRMAX'), max);
                $(otherSpecify).addClass('error_quest_highlight2');
            }
        }
    }
}

// Show error
if (err) {
    strErrorMessage = err;

    $(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>');
} 
Here is the modified custom verification. I had to split it because it was too long.
That code appears to be working for me.  Let's double-check a few more things in your questionnaire.

Your grid question is set to row-oriented, correct?  And each row has been set to not require a response?

Also, the Better Lighthouse Library has been included either as a question on this same page or as code in a global study setting, right?
That is strange. I have checked everything again. The grid question is row-oriented, the rows do not require a response and I have the latest version of the Better Lighthouse Library (I also checked the other version...).
I also tried it again in a new questionnaire, it didn't work there either. And I tried it in lighthouse 9.10.0 (the original questionnair is in 9.8.0). It still does not work for me.

But I found a workaround that I could have thought of earlier. I set the direction to columns and instead of numeric I set the constant sum type, where any amount below the total value is allowed. Now it works exactly as I wanted it to :)

Thank you very much for your patience and your help!
I'm glad to hear you're up and running, but I'm still curious about what is different between your setup and mine.  If you're able to share a .ssi demonstrating the problem with our support team or upload it somewhere I can access, I'd be happy to take a look.
...