Filter questions allow you to display content or questions depending on earlier answers – but sometimes an additional question shall appear directly on the same questionnaire page. In this case, we speak of dynamic content, because the display changes without the browser having transmitted a new HTML page. Dynamic changes of the page require JavaScript, a programming language that runs in the respondent's browser. The server does not learn anything about the changes at first; it only receives the answers after „Next“ has been clicked.
In principle, JavaScript and the Document Object Model (DOM) allow very extensive modifications within a questionnaire page, but this sometimes requires advanced programming skills. This manual is limited to showing or hiding a question depending on an answer.
Tip: If the JavaScript code does not work right away, please use the Developer Tools in the Browser for troubleshooting.
'click' – clicking on an element,'mouseover' – moving the mouse over an element,'change' – selecting an option in a dropdown or changing a text input field,'keypressed' – a key pressstyle), and part of it is the display mode (display). The display mode defines how an element is displayed (block or inline) or that it is not displayed at all (none).id="AB01_01"). If you select the „Inspector“ in the developer tools, you can simply click an element of the page to find the corresponding information. Alternatively, you can display the source code of the HTML page in the browser and search for the corresponding element there._), and qst (e.g., AB01_qst for question „AB01“).Note: You should design the JavaScript code in such a way that it hides the content that is not needed – rather than showing the content that is needed. This has the advantage that respondents with JavaScript disabled can still answer the question, because it is not hidden in the first place.
Note: Screen readers, which allow people with visual impairments to take part in your survey, cannot always cope with dynamic content. Using this function may reduce the accessibility of your questionnaire.
Note: By default, some question types use a different display depending on the screen (responsive layout). In rare cases, the display is not chosen correctly if you show such a question by means of JavaScript. In this case, please set an option other than „dynamic“ for Layout in the question.
Note: If you use a simple selection or scale (i.e., not a multiple choice question) as a filter question and have enabled the option to deselect checked options in a simple selection or scale in the questionnaire, the property checked still returns true instead of false after an option has been deselected. In this case, use the event change instead of click.
Tip: If the respondent sees that one of the options involves additional work, this could influence their answering behavior. A classic filter that asks the second question on the following page may make more sense here.
Depending on a yes/maybe/no question („JN01“, visible selection), an open text question („TX01“) shall be displayed.
The following JavaScript code must be placed on the questionnaire page on which the questions „JN01“ and „TX01“ are located. Either (a) as a text element (display: „HTML code“) that is dragged onto the page, or (b) as an „HTML code“ element on the page.
<script type="text/javascript"> window.addEventListener("load", function() { // Show question TX01 if either 1 or 2 has been selected in JN01 new SoSciTools.ToggleSelection("JN01", [1,2], ["TX01_qst"]); }); </script>
Alternatively, the functionality can also be implemented without SoSciTools as follows:
<script type="text/javascript"> <!-- var optionA = document.getElementById("JN01_01a"); // JN01_01a is the HTML ID of the option "yes" var optionB = document.getElementById("JN01_02a"); // Option "maybe" var optionC = document.getElementById("JN01_03a"); // Option "no" var question = document.getElementById("TX01_qst"); // HTML ID of the text input function toggle() { // The two pipes (||) are a logical "or" // So the condition checks: Is option A selected or is B selected? if (optionA.checked || optionB.checked) { // If "yes" or "maybe" has been selected, the question is displayed // No value ("") uses the default setting (display normally) question.style.display = ""; } else { // The display option "none" hides the question question.style.display = "none"; } } // The function shall be run every time one of the three options is clicked SoSciTools.attachEvent(optionA, "click", toggle); SoSciTools.attachEvent(optionB, "click", toggle); SoSciTools.attachEvent(optionC, "click", toggle); // And it shall also be run right away, so that the display is correct at the beginning // (e.g., hiding the text input at the beginning) toggle(); // --> </script>
For questions to be displayed dynamically, they must already be present (invisibly) on the page. Do not show/hide mandatory questions: Even though the respondent cannot answer invisible questions, SoSci Survey insists on an answer for mandatory questions.
If you want to check the answer to a (possibly) hidden question, use a Individual Response Check. There, you check whether the question was hidden or answered. If not, you display the page again.
Below is an example code matching the example above with the visible selection. Please remember that the PHP code must either be entered at the bottom of the page under „PHP for Processing Responses“ or at the top of the next page of the questionnaire.
if ( // Is question TX01 displayed? ((value('JN01') == 1) || (value('JN01') == 2)) && // Is the answer to the text input question TX01 missing? (trim(value('TX01_01')) == '') ) { // Display the page again repeatPage(); }
Sometimes the same function is used several times on a questionnaire page. Taking the previous example: Let's assume that the page does not only contain one selection with an additional question, but four selection questions with four additional questions.
The obvious solution would be to copy the JavaScript code. However, this does not work without further ado, because the variables (optionA, optionB) and also the name of the function (toggle()) would then get in each other's way. If you decide to copy, you would have to use different names for the variables and functions in each copy. But there is a more elegant way.
Below, the JavaScript code from above is encapsulated in a function or class DynamicFilter(). The 4 tuples of selection and additional question differ in the IDs of the selection question and the additional question. Accordingly, the function has two parameters selectionID and questionID. These parameters are used for the IDs in the first lines: „JN01_01a“ becomes selectionID + „_01“.
This manual omits the <script> tag; if you use the code, you of course have to add <script type=„text/javascript“> at the very beginning and </script> at the end.
function DynamicFilter(selectionID, questionID) { var optionA = document.getElementById(selectionID + "_01a"); // JN01_01a is the HTML ID of the option "yes" var optionB = document.getElementById(selectionID + "_02a"); // Option "maybe" var optionC = document.getElementById(selectionID + "_03a"); // Option "no" var question = document.getElementById(questionID + "_qst"); // HTML ID of the text input function toggle() { // The two pipes (||) are a logical "or" // So the condition checks: Is option A selected or is B selected? if (optionA.checked || optionB.checked) { // If "yes" or "maybe" has been selected, the question is displayed // No value ("") uses the default setting (display normally) question.style.display = ""; } else { // The display option "none" hides the question question.style.display = "none"; } } // The function shall be run every time one of the three options is clicked SoSciTools.attachEvent(optionA, "click", toggle); SoSciTools.attachEvent(optionB, "click", toggle); SoSciTools.attachEvent(optionC, "click", toggle); // And it shall also be run right away, so that the display is correct at the beginning // (e.g., hiding the text input at the beginning) toggle(); }
Everything else remains the same. Now this class function still has to be called to initialize a new instance of the class. This requires the keyword new.
new DynamicFilter("JN01", "TX01");
Together with this call, the code works as in the previous example. But of course, this one line can be repeated several times with further IDs:
new DynamicFilter("JN02", "TX02");
new DynamicFilter("JN03", "TX03");
new DynamicFilter("JN04", "TX04");
This way, the same filter can be used several times on a page very clearly. Of course, it only works this easily if all filter questions and follow-up questions have the same structure. By encapsulating it in a function, however, you can generally avoid the problem that the variables have to be named differently.
An additional question („DD02“) shall be displayed depending on whether a certain option (e.g., the one with the answer code „7“) has been selected in a dropdown selection („DD01“).
<script type="text/javascript"> window.addEventListener("load", function() { // Show question DD02 if option 7 has been selected in the dropdown DD01 new SoSciTools.ToggleDropdown("DD01", [7], ["DD02_qst"]); }); </script>
Alternatively, the function can also be implemented without SoSciTools as follows.
<script type="text/javascript"> <!-- var dropdown = document.getElementById("DD01"); // The input field of question DD01 var question = document.getElementById("DD02_qst"); // The question DD02 to be shown/hidden function toggle() { if (dropdown.value == "7") { // Enter the value (answer code) here for which the second dropdown shall be shown question.style.display = ""; } else { question.style.display = "none"; } } SoSciTools.attachEvent(dropdown, "change", toggle); // Adjust the display when the selection changes SoSciTools.attachEvent(dropdown, "click", toggle); // Also check on click - otherwise the change may only take effect when leaving the dropdown toggle(); // And also ensure the correct display at the beginning // --> </script>
For a ranking question (e.g., „RK01“), the change can be monitored efficiently via the JavaScript instance provided by SoSci Survey. The following example code displays the question „AB01“ if card 2 is placed on rank 1, 2, or 3.
<script> function toggle() { var question = document.getElementById('AB01_qst'); var input = s2.RK01.item(2).input; if ((input.value >= 1) && (input.value <= 3)) { question.style.display = ""; } else { question.style.display = "none"; } } window.addEventListener("load", function() { s2.RK01.addEventListener("click", toggle); }); </script>
The JavaScript class SoSciTools.ToggleSelection can also be used for sliders. As the first parameter, enter the variable ID of the slider item, and as the second, all values for which the question(s) shall be displayed.
<script type="text/javascript"> window.addEventListener("load", function() { // Show question TX01 if a value between 91 and 101 has been set in the slider SL01_01 new SoSciTools.ToggleSelection("SL01_01", [91,92,93,94,95,96,97,98,99,100,101], ["TX01_qst"]); }); </script>
You have a dropdown selection „AB05“ and would like to offer another selection depending on the choice. For this, in the present example, a further selection (sight) has to be created for each city in addition to the first selection (favorite city) and included on the page.
Tip: If you are also considering a visible selection, the extended selection already allows a hierarchical selection of options in a dynamic variant.
Tip: Dynamically showing questions also works in combination with placing questions side by side.
Maybe you cannot work with the default HTML IDs – for example, because you include a question several times on the page and display different items each time. In this case, the questions to be shown are enclosed in DIV elements. This makes the questionnaire page quite long. For the first question, the value 4 pixels is set as spacing to the next question (
).
The following HTML/JavaScript code is saved in a text element (e.g., with the ID „js_dynamic“, display: „HTML code“):
<script type="text/javascript"> <!-- var dropdown = document.getElementById("AB05"); function blender() { // The value corresponds to the answer code in the variables listing var selection = dropdown.value; // However, the value is initially not a number but a text selection = parseInt(selection); // This check is repeated for each question to be shown var question1 = document.getElementById("blockAB06"); if (selection == 1) { // Show question1.style.display = ""; } else { // Hide question1.style.display = "none"; } var question2 = document.getElementById("blockAB07"); if (selection == 2) { question2.style.display = ""; } else { question2.style.display = "none"; } var question3 = document.getElementById("blockAB08"); if (selection == 3) { question3.style.display = ""; } else { question3.style.display = "none"; } } // The function should first be called directly, // since all dropdowns have to be hidden blender(); // Now the function has to be linked to the change event // of the first dropdown SoSciTools.attachEvent(dropdown, "change", blender); SoSciTools.attachEvent(dropdown, "click", blender); // --> </script>
In this example, a scale item with 5 options (1=„not at all“ to 5=„very often“) is to be linked to text fields. The text field for each item should only appear if the option 3, 4 or 5 has been selected.
Furthermore, the solution shall not only be used for a pair of items, but for a whole battery (10 scale items and 10 text input fields, which are represented as Combined Questions). To make this work without having to repeat the whole code 10 times, the JavaScript functionality is encapsulated as a class (function). This class is then called exactly once for each of the 10 items.
In the following example, the items have the following identifiers:
The JavaScript code for the 10 item pairs would look like this. A large part of the code is spent on first finding the selection fields of each scale item (at the top). This has the advantage that the code works independent of the scale level and of DK options.
The core of the function, which shows and hides the input field, is again the element.style.display = "none";
<script type="text/javascript"> /** * Find and list inputs (radio) of the * scale with the identifier itemID. */ function getScaleInputs(itemID) { var inputs = {}; // The regular inputs for (var i=1; i<100; i++) { var inputID = itemID + i; var input = document.getElementById(inputID); if (input) { inputs[i] = input; } else { break; } } // And then there may be DK options for (var i=-1; i>=-3; i--) { var inputID = itemID + "DK" + (-i); if (i == -1) { inputID = itemID + "DK"; } var input = document.getElementById(inputID); if (input) { inputs[i] = input; } } return inputs; } /** * The class that connects the scale item (identifier itemID) * to a text input (or similar) with the identifier inputID. * The array "show" defines for which values the * input field or item should be displayed. */ function linkScaleToInput(itemID, inputID, show) { // First, we need all radio inputs for the item var radio = getScaleInputs(itemID); var element = document.getElementById(inputID); // We need a function to read the value // that was checked in the scale function getValue() { for (var value in radio) { if (radio[value].checked) { return parseInt(value); } } return -9; } // Then we need a function to respond // to the selection function onSelect() { var value = getValue(); // Display, if the value is listed in "show", // or hife vial display=none if (show.indexOf(value) > -1) { element.style.display = ""; } else { element.style.display = "none"; } } for (var value in radio) { radio[value].addEventListener("click", onSelect); } // Use the correct display in the beginning onSelect(); } // One instanmce of the class for each scale item new linkScaleToInput("SK01_01", "TE01_01", [3,4,5]); new linkScaleToInput("SK01_02", "TE01_02", [3,4,5]); new linkScaleToInput("SK01_03", "TE01_03", [3,4,5]); new linkScaleToInput("SK01_04", "TE01_04", [3,4,5]); new linkScaleToInput("SK01_05", "TE01_05", [3,4,5]); new linkScaleToInput("SK01_06", "TE01_06", [3,4,5]); new linkScaleToInput("SK01_07", "TE01_07", [3,4,5]); new linkScaleToInput("SK01_08", "TE01_08", [3,4,5]); new linkScaleToInput("SK01_09", "TE01_09", [3,4,5]); new linkScaleToInput("SK01_10", "TE01_10", [3,4,5]); </script>