Welcome to the LimeSurvey Community Forum

Ask the community, share ideas, and connect with other LimeSurvey users!

JS for selecting two random responses from a multiple choice question

  • dieterdubinsky
  • dieterdubinsky's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
7 years 5 months ago #143121 by dieterdubinsky
Hello dear LimeSurvey-Community,

thank you for doing awesome work and the effort you put into this tool.

I have a question regarding random selection of items from a multiple choice question:
My survey has some items listed in a multiple choice question. Now I want to use up to two of the checked items as placeholders/for piping in the following questions. Googling around I found this:

manual.limesurvey.org/Workarounds:_Manip...estion_for_later_use

which works out just fine (LS 2.5) and was very very helpful. However, it only works for one item. Would there be a way to rewrite the script so it picks two different (!) random items out of all the checked ones and writes them in two different hidden textboxes, so I can use these "answers" in following questions?

I tried doing some work on the script, but obviously did not get very far, as I'm not experienced with JS. I thought it might have something to do with the requirement given in the workaround manual, as it says "Immediately following that question, create a short-text question"
The topic has been locked.
More
7 years 5 months ago #143131 by jelo
Feel free to support a feature request for building dynamic list, which would allow doing random picks without workarounds.
bugs.limesurvey.org/view.php?id=11688

I'm in a love/hate relationship with JavaScript.So no solution by me.But should be possible to add another random pick when the first randomly chosen item is removed from the array before choosing the next item.

The meaning of the word "stable" for users
www.limesurvey.org/forum/development/117...ord-stable-for-users
The topic has been locked.
More
7 years 5 months ago - 7 years 5 months ago #143138 by Deusdeorum
You could probably modify that last part "Load the hidden question with a random item from the array" to something like this:
Code:
    var checkedLength = checkedAnswers.length;
    hiddenInput1 = checkedAnswers[Math.floor(Math.random()*checkedLength)];
    if (checkedLength > 1) {
           do {
                hiddenInput2 = checkedAnswers[Math.floor(Math.random()*checkedLength)];
           } while(hiddenInput1 == hiddenInput2);
    }
 
    $(hiddenInput).val(hiddenInput1+" "+hiddenInput2);

This will fill the short text field to "Answer_X Answer_Y" so you could use regex to set condition on that short text field ((regexMatch("/Answer_X/", short_text_field_question))). Not tested though :)
Last edit: 7 years 5 months ago by Deusdeorum.
The topic has been locked.
  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 years 5 months ago #143140 by tpartner
Instead of the short-text question, I would insert a multiple-short-text with 2 subquestions and shuffle the array something like this:

Code:
<script type="text/javascript" charset="utf-8">    
  $(document).ready(function() {  
 
    // Identify the questions
    var thisQuestion = $('#question{QID}');
    var qHidden = thisQuestion.nextAll('.multiple-short-txt:eq(0)');
    var hiddenInput1 = $('input.text:eq(0)', qHidden);
    var hiddenInput2 = $('input.text:eq(1)', qHidden);
 
    // Hide qHidden
    qHidden.hide();
 
    // Class for "Other
    $('input.text', thisQuestion).closest('.answer-item').addClass('other-item');
 
    // Listener on the checkboxes
    $('input.checkbox', thisQuestion).on('change', function(e) {
      handleChecked();
    });
 
    // Listener on the "Other" input
    $('input.text', thisQuestion).on('keyup change', function(e) {
      setTimeout(function() {
        handleChecked();
      }, 250);
    });
 
    function handleChecked() {
      // Build an array of checked answers
      var checkedAnswers = [];
      $('input.checkbox:checked', thisQuestion).each(function(i) {
        if($(this).closest('.answer-item').hasClass('other-item')) {
          checkedAnswers.push($(this).closest('.answer-item').find('input.text').val());
        }
        else {
          checkedAnswers.push($.trim($(this).nextAll('.label-text:eq(0)').text()));
        }        
      });
 
      // Shuffle the array
      shuffleArray(checkedAnswers);
 
      // Load the hidden question with a random 2 items from the array
      $(hiddenInput1).val(checkedAnswers[0]);
      if(checkedAnswers.length > 1) {
        $(hiddenInput2).val(checkedAnswers[1]);
      }
      else {
        $(hiddenInput2).val('');
      }
 
      // Fire Expression Manager
      checkconditions(hiddenInput1.value, hiddenInput1.name, hiddenInput1.type);
      checkconditions(hiddenInput2.value, hiddenInput2.name, hiddenInput2.type);
    }
    });
 
  function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
      var j = Math.floor(Math.random() * (i + 1));
      var temp = array[i];
      array[i] = array[j];
      array[j] = temp;
    }
    return array;
  }
</script>

Sample survey attached:

File Attachment:

File Name: limesurvey...4794.lss
File Size:20 KB

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
The topic has been locked.
  • dieterdubinsky
  • dieterdubinsky's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
7 years 5 months ago - 7 years 5 months ago #143212 by dieterdubinsky
Wow guys, thanks a lot for the quick support :). The solution given by Tony worked perfectly, you're a genius. I really can't thank you enough.

One more question: Would a kind of script like this also be possible for matrix questions instead of multiple choice? I can't even imagine what that would look like, must be really complicated. If not, I'll just work with what you gave me, that should do as well!

Edit: some more info on that scenario - the question would be "which of the following do you know?" and the options would be "Don't know"; "I know that one (or something like that)" and "I went there during the last xy". The "filter" for the random selection would only apply to those items where the last option was checked.

Thanks again for the help!
Last edit: 7 years 5 months ago by dieterdubinsky.
The topic has been locked.
  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 years 5 months ago #143218 by tpartner
This will load the hidden multi-text question with the array row labels where the last column is checked.

Code:
<script type="text/javascript" charset="utf-8">  $(document).ready(function() {  
 
    // Identify the questions
    var thisQuestion = $('#question{QID}');
    var qHidden = thisQuestion.nextAll('.multiple-short-txt:eq(0)');
    var hiddenInput1 = $('input.text:eq(0)', qHidden);
    var hiddenInput2 = $('input.text:eq(1)', qHidden);
 
    // Hide qHidden
    qHidden.hide();
 
    // Listener on the radios
    $('input.radio', thisQuestion).on('click', function(e) {
      handleChecked();
    });
 
    function handleChecked() {
      // Build an array of checked answers
      var checkedAnswers = [];
      $('input.radio:checked', thisQuestion).each(function(i) {
        if($(this).closest('td.answer-item').is(':last-child')) {
          checkedAnswers.push($(this).closest('tr.answers-list').find('.answertext').text());
        }        
      });
 
      // Shuffle the array
      shuffleArray(checkedAnswers);
 
      // Load the hidden question with 2 random items from the array
      $(hiddenInput1).val(checkedAnswers[0]);
      if(checkedAnswers.length > 1) {
        $(hiddenInput2).val(checkedAnswers[1]);
      }
      else {
        $(hiddenInput2).val('');
      }
 
      // Fire Expression Manager
      checkconditions(hiddenInput1.value, hiddenInput1.name, hiddenInput1.type);
      checkconditions(hiddenInput2.value, hiddenInput2.name, hiddenInput2.type);
    }
    });
 
  function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
      var j = Math.floor(Math.random() * (i + 1));
      var temp = array[i];
      array[i] = array[j];
      array[j] = temp;
    }
    return array;
  }
</script>

Sample survey attached:

File Attachment:

File Name: limesurvey...94-2.lss
File Size:21 KB

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
The topic has been locked.
  • dieterdubinsky
  • dieterdubinsky's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
7 years 5 months ago - 7 years 5 months ago #143220 by dieterdubinsky

tpartner wrote: This will load the hidden multi-text question with the array row labels where the last column is checked.

Code:
<script type="text/javascript" charset="utf-8">  $(document).ready(function() {  
 
    // Identify the questions
    var thisQuestion = $('#question{QID}');
    var qHidden = thisQuestion.nextAll('.multiple-short-txt:eq(0)');
    var hiddenInput1 = $('input.text:eq(0)', qHidden);
    var hiddenInput2 = $('input.text:eq(1)', qHidden);
 
    // Hide qHidden
    qHidden.hide();
 
    // Listener on the radios
    $('input.radio', thisQuestion).on('click', function(e) {
      handleChecked();
    });
 
    function handleChecked() {
      // Build an array of checked answers
      var checkedAnswers = [];
      $('input.radio:checked', thisQuestion).each(function(i) {
        if($(this).closest('td.answer-item').is(':last-child')) {
          checkedAnswers.push($(this).closest('tr.answers-list').find('.answertext').text());
        }        
      });
 
      // Shuffle the array
      shuffleArray(checkedAnswers);
 
      // Load the hidden question with 2 random items from the array
      $(hiddenInput1).val(checkedAnswers[0]);
      if(checkedAnswers.length > 1) {
        $(hiddenInput2).val(checkedAnswers[1]);
      }
      else {
        $(hiddenInput2).val('');
      }
 
      // Fire Expression Manager
      checkconditions(hiddenInput1.value, hiddenInput1.name, hiddenInput1.type);
      checkconditions(hiddenInput2.value, hiddenInput2.name, hiddenInput2.type);
    }
    });
 
  function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
      var j = Math.floor(Math.random() * (i + 1));
      var temp = array[i];
      array[i] = array[j];
      array[j] = temp;
    }
    return array;
  }
</script>

Sample survey attached:

File Attachment:

File Name: limesurvey...94-2.lss
File Size:21 KB


Thanks again, Tony :) You are a lifesaver! I will try to implement that instead of the multiple choice question.

In the meantime, another issue with the survey came up: Sometimes when I test the survey and I only claim to know one of the items, the variable qHidden is empty and the item is written in qHidden2 or vice versa. So if I only need to show one block of questions because the participant only knows one option, he or she would sometimes get questions with empty placeholders {qHidden_1} or {qHidden_2}. Is there any chance you also know something about this?

Edit: What I am trying to do is have two blocks of items each dealing with oneof the given options. I want to set a condition with "count" that the second block is only displayed if there were actually two or more items checked.
Last edit: 7 years 5 months ago by dieterdubinsky.
The topic has been locked.
  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 years 5 months ago #143233 by tpartner

Sometimes when I test the survey and I only claim to know one of the items, the variable qHidden is empty and the item is written in qHidden2 or vice versa.

If there is only one eligible option, it will be written to the first sub-question of the hidden question.

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
The topic has been locked.
  • dieterdubinsky
  • dieterdubinsky's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
7 years 5 months ago - 7 years 5 months ago #143235 by dieterdubinsky

tpartner wrote:

Sometimes when I test the survey and I only claim to know one of the items, the variable qHidden is empty and the item is written in qHidden2 or vice versa.

If there is only one eligible option, it will be written to the first sub-question of the hidden question.

Alright, thank you :) I probably messed up somewhere along the way. I'll have a thorough look again and hope that I can find it.

Thanks a lot for helping me out with this. This is an awesome community!
Last edit: 7 years 5 months ago by dieterdubinsky.
The topic has been locked.
  • dieterdubinsky
  • dieterdubinsky's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
7 years 4 months ago #143393 by dieterdubinsky
Hello, it's me again :).

I'm still working on the survey and was wondering if it would be possible to set some kind of quota regarding the placeholders. For example, can the short text field inputs for qHidden_1 and qHidden_2 also be transferred to a hidden MC question where you could set a quota? Or, alternatively, could you just input a hidden MC question with all possible options where the items would only be visible if they were chosen for qHidden? And then maybe check both that are still visible and set a quota for that?

Imagine having a list like this:

What do you like?
- Apples
- Bananas
- Strawberries
- Grapefruits
- Grapes

And you would want two of those chosen at random, but only about 200 people who get asked regarding "Apples" (as many people would choose apples), so you won't have a sample of 1000 people where 800 went with apples and only 100 with grapefruits.

Would that be possible with some JS workaround? I read about hiding single choice questions etc., but I couldn't find anything on placeholders.
The topic has been locked.
  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 years 4 months ago #143405 by tpartner
Search the forum for "hidden multiple-choice question". You should find lots of tips on how to toggle them.

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
The topic has been locked.
  • dieterdubinsky
  • dieterdubinsky's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
7 years 4 months ago #143421 by dieterdubinsky
Thank you again, I'll try my best. If I find anything that works, I will post it here.
The topic has been locked.

Lime-years ahead

Online-surveys for every purse and purpose