- Posts: 181
- Thank you received: 29
Ask the community, share ideas, and connect with other LimeSurvey users!
// Question Order Reuse (LS6 question-by-question compatible) window.LSAnswerOrder = (function () { function isVisible(el) { if (!el) return false; return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); } function getVisibleQuestion() { // Prefer the visible question container var list = document.querySelectorAll('div.question-container'); for (var i = 0; i < list.length; i++) { if (isVisible(list[i])) return list[i]; } // Fallback return document.querySelector('div[id^="question"]'); } function getQidFromQuestionDiv(q) { // q.id like "question20855" var m = (q && q.id) ? q.id.match(/^question(\d+)$/) : null; return m ? m[1] : ''; } function dedupeKeepOrder(arr) { var seen = Object.create(null); var out = []; for (var i = 0; i < arr.length; i++) { var v = arr[i]; if (v && !seen[v]) { seen[v] = true; out.push(v); } } return out; } function codeFromInput(inp, qid) { if (!inp) return ''; // For list radio / list checkbox: value is the answer code (e.g., "1","2"...) var v = inp.value; if (v && v !== 'Y' && v !== 'N') return v; // For multiple choice and many arrays: value is "Y" (or not helpful), // so get code from the name after X<qid> var name = inp.getAttribute('name') || ''; if (!qid || !name) return ''; var marker = 'X' + qid; var idx = name.lastIndexOf(marker); if (idx === -1) return ''; var after = name.substring(idx + marker.length); // e.g. "1" or "SQ001" or "SQ001_1" // If arrays encode extra suffix after underscore, keep just the row code // (safe for MC too: "1" has no underscore) var us = after.indexOf('_'); if (us > -1) after = after.substring(0, us); return after; } function capture() { var q = getVisibleQuestion(); if (!q) return; var qid = getQidFromQuestionDiv(q); var codes = []; // Dropdown var sel = q.querySelector('select'); if (sel) { var opts = sel.querySelectorAll('option'); for (var i = 0; i < opts.length; i++) { var val = opts[i].getAttribute('value'); if (val) codes.push(val); } } // Array rows: capture row order by reading first control name in each row else if (q.querySelectorAll('table tbody tr').length) { var rows = q.querySelectorAll('table tbody tr'); for (var r = 0; r < rows.length; r++) { var ctrl = rows[r].querySelector('input,select,textarea'); var code = codeFromInput(ctrl, qid); if (code) codes.push(code); } } // Lists / multiple choice: capture the displayed LI order from the answers list else { var answerLis = q.querySelectorAll('ul.ls-answers > li'); for (var l = 0; l < answerLis.length; l++) { var inp = answerLis[l].querySelector('input[type="radio"], input[type="checkbox"]'); var code2 = codeFromInput(inp, qid); if (code2) codes.push(code2); } } codes = dedupeKeepOrder(codes); sessionStorage.setItem('answerorder', codes.join(',')); console.log('Stored answerorder:', codes.join(',')); } function apply() { var orderStr = sessionStorage.getItem('answerorder') || ''; if (!orderStr) return; var desired = orderStr.split(','); var q = getVisibleQuestion(); if (!q) return; var qid = getQidFromQuestionDiv(q); // Dropdown: reorder options var sel = q.querySelector('select'); if (sel) { var map = {}; var opts = Array.prototype.slice.call(sel.querySelectorAll('option')); for (var i = 0; i < opts.length; i++) map[opts[i].value] = opts[i]; var empty = map[''] || null; sel.innerHTML = ''; if (empty) sel.appendChild(empty); for (var d = 0; d < desired.length; d++) { if (map[desired[d]]) sel.appendChild(map[desired[d]]); } console.log('Applied order to dropdown'); return; } // Array: reorder table rows var tbody = q.querySelector('table tbody'); if (tbody && tbody.querySelectorAll('tr').length) { var rowByCode = {}; var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr')); for (var r = 0; r < rows.length; r++) { var ctrl = rows[r].querySelector('input,select,textarea'); var code = codeFromInput(ctrl, qid); if (code) rowByCode[code] = rows[r]; } for (var d2 = 0; d2 < desired.length; d2++) { if (rowByCode[desired[d2]]) tbody.appendChild(rowByCode[desired[d2]]); } console.log('Applied order to array rows'); return; } // List / Multiple choice: reorder answer LIs (this fixes your Q2) var ul = q.querySelector('ul.ls-answers'); if (ul) { var lis = ul.querySelectorAll(':scope > li'); var liByCode = {}; for (var l = 0; l < lis.length; l++) { var inp = lis[l].querySelector('input[type="radio"], input[type="checkbox"]'); var c = codeFromInput(inp, qid); if (c) liByCode[c] = lis[l]; } for (var d3 = 0; d3 < desired.length; d3++) { if (liByCode[desired[d3]]) ul.appendChild(liByCode[desired[d3]]); } console.log('Applied order to list/multiple-choice'); } } return { capture: capture, apply: apply }; })();
LSAnswerOrder.capture();
LSAnswerOrder.apply();
Please Log in to join the conversation.
Just thought I would share this with everyone. We quite often get asked if we can keep the order of answers from question to question when the first list of answers has been randomised.
Please Log in to join the conversation.
Please Log in to join the conversation.
What I have been asked to do is keep this first order across multiple follow up questions
Please Log in to join the conversation.
Please Log in to join the conversation.
Please Log in to join the conversation.
Please Log in to join the conversation.
Please Log in to join the conversation.
<script type="text/javascript" charset="utf-8" data-author="Tony Partner"> $(document).on('ready pjax:scriptcomplete',function(){ //Identify the questions var thisQuestion = $('#question{QID}'); var hiddenQuestion = $(thisQuestion).nextAll('.text-short:eq(0)'); // Create an array of answer codes var answerCodes = ; $('li.answer-item', thisQuestion).each(function(i) { answerCodes.push($(this).attr('id').split('X{QID}')[1]); }); // Load the hidden question $('input:text', hiddenQuestion).val(answerCodes); }); </script>
<script type="text/javascript" charset="utf-8" data-author="Tony Partner"> $(document).on('ready pjax:scriptcomplete',function(){ //Identify this question var thisQuestion = $('#question{QID}'); var thisAnswerList = $('li.answer-item:eq(0)', thisQuestion).parent(); // Retrieve the answer codes from the "randomOrder" question var answerCodes = '{RandOrder}'.split(','); // Loop through the answer codes $.each(answerCodes, function(i, val) { // Move the answer item $(thisAnswerList).append($('li.answer-item[id$="X{QID}'+val+'"]', thisQuestion)); }); }); </script>
<script type="text/javascript" data-author="Tony Partner"> $(document).on('ready pjax:scriptcomplete',function(){ //Identify this question var thisQuestion = $('#question{QID}'); var thisAnswerList = $('tr.answers-list:eq(0)', thisQuestion).parent(); // Retrieve the answer codes from the "randomOrder" question var answerCodes = '{RandOrder}'.split(','); // Loop through the answer codes $.each(answerCodes, function(i, val) { // Move the answer item $(thisAnswerList).append($('tr.answers-list[id$="X{QID}'+val+'"]', thisQuestion)); }); }); </script>
<script type="text/javascript" data-author="Tony Partner"> $(document).on('ready pjax:scriptcomplete',function(){ //Identify this question var thisQuestion = $('#question{QID}'); var thisAnswerList = $('tr.subquestion-list:eq(0)', thisQuestion).parent(); // Retrieve the answer codes from the "RandOrder" question var answerCodes = '{RandOrder}'.split(','); // Loop through the answer codes $.each(answerCodes, function(i, val) { // Move the answer item $(thisAnswerList).append($('tr.subquestion-list[id$="X{QID}'+val+'"]', thisQuestion)); }); }); </script>
Please Log in to join the conversation.