Question

I'm working on a product configurator. I use Ractivejs.
I have two problems.

  1. if you check option1 in step1, in step2 option1 is also checked (why?)
  2. i need a way to hide color blue, if you choose Product 2 in the first step

template:

{{#steps[currentStep].options:i}}
    <div class='radio'>
      <label>
        <input type='radio' name='group{{currentStep}}' id='radio{{currentStep}}{{i}}' value='option{{currentStep}}{{i}}'>
        {{name}}
      </label>
    </div>
{{/steps[currentStep].options}}
<button on-click='gotoStep: {{currentStep + 1}}'>next</button>

Javascript:

var ractive, stepsData;

stepsData = [
    { name: 'Products', options: [
        { name: 'Product 1', price: 100 },
        { name: 'Product 2', price: 120 }
    ]},
    { name: 'Color', options: [
        { name: 'Black', price: 0},
        { name: 'White', price: 5 },
        { name: 'Blue', price: 20 }
    ]}
];

ractive = new Ractive({
    el: '#template',
    template: '#tempMain',
    data: {
        steps: stepsData,
        currentStep: 0
    }
});

ractive.on( 'gotoStep', function ( event, step ) {
  this.set( 'currentStep', step );
});
Was it helpful?

Solution

You've got to get the radio group value to append to the right object. For this particular example, that would might mean putting it onto the options object:

{{#steps[currentStep].options:i}}
    <div class='radio'>
      <label>
          <input type='radio' name='{{../value}}' value='{{i}}'/>
        {{name}}
      </label>
    </div>
{{/}}

See http://jsfiddle.net/x63VW/1/

UPDATE: Really you should consider moving your answers to a separate object. (There's a bug in ractive that makes this template a bit longer than it needs to be, I'll walk through that next). Full example is here: http://jsfiddle.net/x63VW/3/.

{{# steps[currentStep] }}
    {{# { stepName: .name, options: options } }}
    {{#options:i}}
        {{# !exclude(stepName, name) }}
        <div class='radio'>
          <label>
              <input type='radio' name='{{responses[stepName]}}' value='{{name}}'/>
              {{name}}
          </label>
        </div>
        {{/}}
    {{/}}
    {{/}}
{{/}}

<button on-click='gotoStep: {{currentStep + -1}}'>prev</button>
<button on-click='gotoStep: {{currentStep + 1}}'>next</button>
<br>
responses:
{{#responses:r}}
    <li>{{r}}: {{.}}</li>
{{/}}

The key here is creating a responses object with a property for every step: responses[stepName]. This also enables you to provide existing responses.

In order to get the radio inputs to update, I'm causing the section to go falsey before updating:

ractive.on( 'gotoStep', function ( event, step ) {
  this.set( 'currentStep', null ); //workaround for bug
  this.set( 'currentStep', step );
});

Which means the initial section has to be capable of returning a falsey value:

{{# steps[currentStep] }}
//this would throw:
{{# steps[currentStep].options }}

The aliasing is a nicety to avoid ../../name and referencing steps[currentStep] multiple times:

{{# { stepName: .name, options: options } }}

The exclusion is managed via a filter function. Which is likely unless your logic is very simplistic.

ractive = new Ractive({
    el: '#template',
    template: '#tempMain',
    data: {
        steps: stepsData,
        currentStep: 0,
        exclude: function(stepName, optName){
            if(stepName==='Color' && optName=='Blue'){
                return this.get('responses.Products')==='Product 2'
            }
        }
    }
});

You probably would create some type of map for steps and answers and what to exclude. But this should give you an approach.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top