Have an idea?

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

Pricing ladder from question library

I'm using the pricing ladder question from the library and later in the survey I need to refer to  'PriceLaddering_Price' which is fine but also need to reference the score they gave which comes from 'PriceLaddering_Responses' which is a comma separated text field.  I have 4 price points ($5,$10,$15,$20) Is there a way to get the responses stored as separate variables. My respone list is a 4 point scale (Def would - Def would not). Is there a way to store these responses in 4 separate variables e.g 'PriceLaddering_ResponseTen' would store the 1-4 score given when $10 price was shown (would be left blank if not shown). Thanks in advance!
asked Aug 24 by Paul Kallis (250 points)
This would be a nice addition.  I am fielding one now with three different price ladder questions.  I am creating the variables I need and populating using the _Responses variable.  I'm separating the responses into different columns  and then based on the start point and first score I can determine if we are moving up or down in price points so I can populate accordingly.

The idea here was that a Gabor Granger question was meant more for the end result vs. the steps in getting there.  However, most of my clients want to see all the responses in different variables.

1 Answer

0 votes
 
Best answer
I added four new variables to the question, named "_Response1" through "_Response4."  Then I modified the script as such:

<input name="[% QuestionName() %]_Price" id="[% QuestionName() %]_Price" type="hidden" value=""/>
<input name="[% QuestionName() %]_StartPrice" id="[% QuestionName() %]_StartPrice" type="hidden" value=""/>
<input name="[% QuestionName() %]_Responses" id="[% QuestionName() %]_Responses" type="hidden" value=""/>
<input name="[% QuestionName() %]_Response1" id="[% QuestionName() %]_Response1" type="hidden" value=""/>
<input name="[% QuestionName() %]_Response2" id="[% QuestionName() %]_Response2" type="hidden" value=""/>
<input name="[% QuestionName() %]_Response3" id="[% QuestionName() %]_Response3" type="hidden" value=""/>
<input name="[% QuestionName() %]_Response4" id="[% QuestionName() %]_Response4" type="hidden" value=""/>

<div class="priceLadderingContainer"></div>

<style>
#[% QuestionName() %]_div {
    transition: background 0.5s linear;
}

.priceLadderingFinished {
    display: none;
}

.priceLadderingButton {
    display: block;
    width: 200px;
    margin: 10px 0px;
    padding: 5px;
    cursor: pointer;
}

.priceLadderingButton:hover {
    background-color: #CDCDCD;
}
</style>

<script>
$(document).ready(function(){
    var prices = ['$1', '$2', '$3', '$4'];
    var startPosition = 'middle'; // the position of the first price to show, or 'middle' to automatically select middle price, or 'random' to select random starting price
    // Price laddering experiments are typically performed with either two acceptables and three unacceptables, or one acceptable and one unaccpetable (yes and no)
    var acceptableResponses = ['Extremely likely', 'Very likely'];
    var unacceptableResponses = ['Somewhat likely', 'Not very likely', 'Not at all likely'];
    var noneResponse = 'NONE';
    
    // initialize price
    var priceLadderingPosition;
    switch (startPosition.toString().toLowerCase()) {
        case 'middle':
            priceLadderingPosition = Math.ceil(prices.length / 2);
            break;
        case 'random':
            priceLadderingPosition = Math.ceil(Math.random() * prices.length)
            break;
        default:
            priceLadderingPosition = Number(startPosition);
            break;
    }
    $('#[% QuestionName() %]_div .priceLadderingPrice').text(prices[priceLadderingPosition - 1]);
    
    // reset individual responses
    $('#[% QuestionName() %]_Response1').val('');
    $('#[% QuestionName() %]_Response2').val('');
    $('#[% QuestionName() %]_Response3').val('');
    $('#[% QuestionName() %]_Response4').val('');
    
    // create buttons
    var responseCounter = 1;
    acceptableResponses.forEach(function(response){
        $('#[% QuestionName() %]_div .priceLadderingContainer').append('<button type="button" class="priceLadderingButton acceptable" data-priceladdering="' + responseCounter + '">' + response + '</button>');
        responseCounter++;
    });
    unacceptableResponses.forEach(function(response){
        $('#[% QuestionName() %]_div .priceLadderingContainer').append('<button type="button" class="priceLadderingButton unacceptable" data-priceladdering="' + responseCounter + '">' + response + '</button>');
        responseCounter++;
    });
    
    // click events
    var priceLadderingPreviousPosition;
    var firstClick = true;
    var responsesSep = '';
    $('#[% QuestionName() %]_div .priceLadderingButton').click(function(){
        if (firstClick) {
            $('#[% QuestionName() %]_Price').val('');
            $('#[% QuestionName() %]_StartPrice').val(prices[priceLadderingPosition - 1]);
            $('#[% QuestionName() %]_Responses').val('');
            firstClick = false;
        }
        
        var resp = $(this).data('priceladdering');
        $('#[% QuestionName() %]_Responses').val($('#[% QuestionName() %]_Responses').val() + responsesSep + resp);
        responsesSep = ',';
        
        $('#[% QuestionName() %]_Response' + priceLadderingPosition).val(resp);
    
        var acceptable = $(this).is('.acceptable');
        if (priceLadderingPosition == 1 && !acceptable) {
            finishPriceLaddering('[% QuestionName() %]', noneResponse);
        }
        else if ((priceLadderingPosition == prices.length && acceptable) ||
            (acceptable && priceLadderingPreviousPosition && priceLadderingPosition < priceLadderingPreviousPosition)) {
            finishPriceLaddering('[% QuestionName() %]', prices[priceLadderingPosition - 1]);
        }
        else if ((priceLadderingPosition == prices.length && !acceptable && priceLadderingPreviousPosition) ||
            (priceLadderingPosition == 1 && acceptable && priceLadderingPreviousPosition) ||
            (!acceptable && priceLadderingPreviousPosition && priceLadderingPosition > priceLadderingPreviousPosition)) {
            finishPriceLaddering('[% QuestionName() %]', prices[priceLadderingPreviousPosition - 1]);
        }
        else {
            priceLadderingPreviousPosition = priceLadderingPosition;
            priceLadderingPosition += acceptable ? 1 : -1;
            updatePriceLaddering('[% QuestionName() %]', prices[priceLadderingPosition - 1]);
        }
    });
})

function updatePriceLaddering(question, price) {
    var qdiv = $('#' + question + '_div');
    $(qdiv).find('.priceLadderingPrice').text(price);
    $(qdiv).css({
        'transition': 'background-color 0.5s ease-in-out',
        'background-color': '#e6ffff'
    });
    var interval = setInterval(function(){
        $(qdiv).css({
            'transition': 'background-color 1s ease-in-out',
            'background-color': 'transparent'
        });
        clearInterval(interval);
    }, 500);
}

function finishPriceLaddering(question, price) {
    $('#' + question + '_Price').val(price);
    var qdiv = $('#' + question + '_div');
    $(qdiv).find('.priceLadderingButton').prop('disabled', true).css('cursor', 'default');
    $(qdiv).find('.priceLadderingFinished').show();
}
</script>
answered Aug 24 by Zachary Platinum Sawtooth Software, Inc. (156,375 points)
selected Aug 24 by Paul Kallis
Exactly what I needed. Thanks Zachary!
Hi Zachary, the buttons appear rectangular on PC and android but on iPhones they have a radius when initially shown but once you select a button it turns rectangular again. Is there a way to make sure the buttons always show rectangular. I've tried
border-radius: 0;
-webkit-appearance: none;
but neither work. Can you help?
cheers,
Paul
I don't have an iOS device to test with, so I've had to just go with Googling on this one.  I found this StackOverflow page, which you may have already seen:

https://stackoverflow.com/questions/5263260

It looks like you may also want to try adding this rule to the ".priceLadderingButton" CSS:

-webkit-border-radius: 0px;


For either of our potential solutions (or even for both solutions combined), it may be necessary to add a "!important" flag to these CSS rules.

Please give that a try and tell me how it goes.
Got it working!. Put this in my header.

textarea,
input.text,
input[type="text"],
input[type="button"],
input[type="submit"],
.input-checkbox {
-webkit-appearance: none;
border-radius: 0;
...