I've just finished my Gabor-Granger question. It was a bit of a unique challenge from a design perspective, so I would be interesting in hearing any thoughts on user experience and clarity and all that fun stuff.
To build it, start with a free format question. The free format requires a hidden, text variable named "_Price."
Somewhere in the question texts, place something like this to display the current price to the respondent:
How likely are you to buy this product for <b><span class="gaborGrangerPrice"></span></b>?
Optionally place something like this elsewhere in the question texts to inform respondents that the question is complete:
<span class="gaborGrangerFinished"><i>Your responses have been recorded. Please continue with the survey.</i></span>
Finally, set the question HTML to this:
<input name="[% QuestionName() %]_Price" id="[% QuestionName() %]_Price" type="hidden" value=""/>
<div class="gaborGrangerContainer"></div>
<style>
.gaborGrangerFinished {
display: none;
}
.gaborGrangerButton {
display: block;
width: 200px;
margin: 10px 0px;
padding: 5px;
cursor: pointer;
}
.gaborGrangerButton:hover {
background-color: #CDCDCD;
}
</style>
<script>
$(document).ready(function(){
var prices = ['$1', '$2', '$3', '$4', '$5'];
var startPosition = 'middle'; // the position of the first price to show, or 'middle' to automatically select middle price; 'random' to select random starting price
// Gabor-Granger experiments are typically performed with either two acceptables and three unacceptables, or one acceptable and one unaccpetable
var acceptableResponses = ['Extremely likely', 'Very likely'];
var unacceptableResponses = ['Somewhat likely', 'Not very likely', 'Not at all likely'];
var noneResponse = 'NONE';
// initialize price
var gaborPosition;
switch (startPosition.toString().toLowerCase()) {
case 'middle':
gaborPosition = Math.ceil(prices.length / 2);
break;
case 'random':
gaborPosition = Math.ceil(Math.random() * prices.length)
break;
default:
gaborPosition = Number(startPosition);
break;
}
$('#[% QuestionName() %]_div .gaborGrangerPrice').text(prices[gaborPosition - 1]);
// create buttons
acceptableResponses.forEach(function(response){
$('#[% QuestionName() %]_div .gaborGrangerContainer').append('<button type="button" class="gaborGrangerButton acceptable">' + response + '</button>');
});
unacceptableResponses.forEach(function(response){
$('#[% QuestionName() %]_div .gaborGrangerContainer').append('<button type="button" class="gaborGrangerButton unacceptable">' + response + '</button>');
});
// click events
var gaborPreviousPosition;
$('#[% QuestionName() %]_div .gaborGrangerButton').click(function(){
var acceptable = $(this).is('.acceptable');
if (gaborPosition == 1 && !acceptable) {
finishGaborGranger('[% QuestionName() %]', noneResponse);
}
else if ((gaborPosition == prices.length && acceptable) ||
(acceptable && gaborPreviousPosition && gaborPosition < gaborPreviousPosition)) {
finishGaborGranger('[% QuestionName() %]', prices[gaborPosition - 1]);
}
else if ((gaborPosition == prices.length && !acceptable && gaborPreviousPosition) ||
(gaborPosition == 1 && acceptable && gaborPreviousPosition) ||
(!acceptable && gaborPreviousPosition && gaborPosition > gaborPreviousPosition)) {
finishGaborGranger('[% QuestionName() %]', prices[gaborPreviousPosition - 1]);
}
else {
gaborPreviousPosition = gaborPosition;
gaborPosition += acceptable ? 1 : -1;
updateGaborGranger('[% QuestionName() %]', prices[gaborPosition - 1]);
}
});
})
function updateGaborGranger(question, price) {
var qdiv = $('#' + question + '_div');
$(qdiv).fadeOut(500, function(){
$(qdiv).find('.gaborGrangerPrice').text(price);
var bgColor = $(qdiv).css('background-color');
$(qdiv).css('background-color', 'lightcyan');
$(qdiv).fadeIn(1000, function(){
$(qdiv).css('background-color', bgColor);
});
});
}
function finishGaborGranger(question, price) {
$('#' + question + '_Price').val(price);
var qdiv = $('#' + question + '_div');
$(qdiv).find('.gaborGrangerButton').prop('disabled', true).css('cursor', 'default');
$(qdiv).find('.gaborGrangerFinished').show();
}
</script>
Line 24 should be updated with the relevant prices, from lowest to highest.
Line 25 can be updated to set which price a respondent starts on.
Line 27 and 28 can be updated with the acceptable and unacceptable response options. From what I can tell, most Gabor-Granger experiments have (A) two acceptables and three unacceptables, or (B) an acceptable "Yes" and an unacceptable "No."
Line 29 can be updated with the value to be recorded if a respondent says that the lowest price is unacceptable.