I need a form with multiple steps where the first step restricts options in the successive steps.
So below is an example of use:
User selects from 4 global options
After all these selections, this form has to show a final price based on the options user selected in the FIRST STEP. No matter what choices were selected in successive steps.
When this form shows final price, user has to click SUBMIT button and send this result with all these options through an email.
Can someone help me in figuring out the javascript required to do this? Most important thing right now for me is to figure out 'restrictions codes' in multiple items choice boxes.
This is the form I was thinking about:
<form action="" id="menuform" onsubmit="return false;">
<fieldset>
<legend>Select one of this four menus</legend>
<label >Menu Option</label>
<input type="radio" name="selectedmenu" value="Menu1"
onclick="calculateTotal()" />
Menu 1 - serves 8 courses ($20)
<input type="radio" name="selectedmenu" value="Menu2"
onclick="calculateTotal()" />
Menu 2 - serves 12 courses ($25)
<input type="radio" name="selectedmenu" value="Menu3"
onclick="calculateTotal()" />
Menu 3 - serves 16 courses ($35)
<input type="radio" name="selectedmenu" value="Menu4"
onclick="calculateTotal()" />
Menu 4 - serves 30 courses ($75)
<label >Filling</label>
<select id="filling" name='filling'
onchange="calculateTotal()">
<option value="dish1">Dish 1 ($1)</option>
<option value="dish2">Dish 2 ($5)</option>
<option value="dish3">Dish 3 ($5)</option>
(more...)
</select>
<br/>
<div id="totalPrice"></div>
</fieldset>
</form>
Then, for Javascript code I was trying with this to store and return some values but my problem is how to force to select an exact number of options in the SECOND STEP:
var menu_prices = new Array();
menu_prices["Menu1"]=20;
menu_prices["Menu2"]=25;
menu_prices["Menu3"]=35;
menu_prices["Menu4"]=75;
function getMenuPrice()
{
var menuPrice=0;
var theForm = document.forms["menuform"];
var selectedMenu = theForm.elements["selectedmenu"];
for(var i = 0; i < selectedMenu.length; i++)
{
if(selectedMenu[i].checked)
{
menuPrice = menu_prices[selectedMenu[i].value];
break;
}
}
return menuPrice;
}
function getTotal()
{
var menuPrice = getMenuPrice() + getOtherOptionsPrices();
document.getElementById('totalPrice').innerHTML =
"Total Price For Menu $"+menuPrice;
}
Structure your HTML markup carefully, which helps you to target elements via JavaScript easily. Especially, using data-attributes on radio buttons for quantity and price which could be then easily retrieved in respective event handlers. Something like this:
<form action="" method="post" id="menuform" name="menuform">
<fieldset>
<legend>Select menu option</legend>
<label>
<input type="radio" name="selectedmenu" checked value="menu01" data-qty='3' data-price='20' />
<span>1 - serves 3 courses ($20)</span>
</label>
...
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<select id="fillings" name="fillings" size="6" multiple>
<option value="1">Dish 1 ($1)</option>
...
<fieldset>
<legend>Checkout</legend>
<div id="totalPrice"></div>
<input type="submit" value="Submit" />
</fieldset>
<fieldset>
<legend>Messages</legend>
<p id="result"></p>
</fieldset>
</form>
Identify and select all elements that you'll need:
var menuform = document.getElementById('menuform'),
radios = document.getElementsByName('selectedmenu'),
fillings = document.getElementById('fillings'),
fillingsPrompt = document.getElementById('fillingsPrompt'),
totalPrice = document.getElementById('totalPrice'),
result = document.getElementById('result'),
fillingsAllowed = 0, currentSelection = [], currency = '$'
;
Add event listeners to your radio buttons, select, and the submit button:
menuform.addEventListener('submit', handleSubmit);
fillings.addEventListener('change', handleFillings);
for (var i = radios.length; i--; ) {
radios[i].addEventListener('change', handleLimit);
}
Code the actual event handlers:
// When radio buttons are selected, update parameters for limit
function handleLimit(e) { updateParameters(e.target); }
// When options are selected in the dropdown,
// check against the limit and reset the selection if it exceeds
function handleFillings(e) {
var count = getSelectedCount();
if (count > fillingsAllowed) { resetSelect(); }
else { currentSelection = getSelectedValues(); }
}
// When submit button is clicked,
// check the count of selection against the limit, and
// show appropriate error message
function handleSubmit(e) {
var count = getSelectedCount();
e.preventDefault();
if (count != fillingsAllowed) {
result.textContent = 'Must select exactly ' + fillingsAllowed + ' fillings!';
} else {
result.textContent = 'Ok. ';
}
}
And then code all the helper functions used in the handlers above:
function updateParameters(elem) {
// update the limit based on quantity data attribute on radio
fillingsAllowed = elem.getAttribute('data-qty');
// show the amount based on price data-attribute
totalPrice.textContent = 'Amount: ' + currency + elem.getAttribute('data-price');
// show the hint on legend of fieldset for selecting options
fillingsPrompt.textContent = 'Select ' + fillingsAllowed + ' fillings';
}
// iterate options and get count of selected ones
function getSelectedCount() {
var options = fillings.options, count = 0;
for (var i=0; i < options.length; i++) {
if (options[i].selected) count++;
}
return count;
}
// iterate options and get selected values in an array
function getSelectedValues() {
var options = fillings.options, values = [0];
for (var i=0; i < options.length; i++) {
if (options[i].selected) values.push(options[i].value);
}
return values;
}
// remove selection from all options, and
// re-select based on the array used in the previous function
function resetSelect() {
var options = fillings.options;
for (var i=0; i < options.length; i++) {
options[i].selected = false;
if (currentSelection.indexOf(options[i].value) != -1) {
options[i].selected = true;
}
}
}
Everything put together, the demo looks like this:
Fiddle: https://jsfiddle.net/abhitalks/L813qudw/
Snippet:
var menuform = document.getElementById('menuform'),
radios = document.getElementsByName('selectedmenu'),
fillings = document.getElementById('fillings'),
fillingsPrompt = document.getElementById('fillingsPrompt'),
totalPrice = document.getElementById('totalPrice'),
result = document.getElementById('result'),
fillingsAllowed = 0, currentSelection = [], currency = '$'
;
// listen to events
menuform.addEventListener('submit', handleSubmit);
fillings.addEventListener('change', handleFillings);
for (var i = radios.length; i--; ) {
radios[i].addEventListener('change', handleLimit);
}
// event handlers
function handleLimit(e) { updateParameters(e.target); }
function handleFillings(e) {
var count = getSelectedCount();
if (count > fillingsAllowed) { resetSelect(); }
else { currentSelection = getSelectedValues(); }
}
function handleSubmit(e) {
var count = getSelectedCount();
e.preventDefault();
if (count != fillingsAllowed) {
result.textContent = 'Must select exactly ' + fillingsAllowed + ' fillings!';
} else {
result.textContent = 'Ok. ';
}
}
// fire initial update based on the first radio
updateParameters(radios[0]);
// helper functions
function updateParameters(elem) {
fillingsAllowed = elem.getAttribute('data-qty');
totalPrice.textContent = 'Amount: ' + currency + elem.getAttribute('data-price');
fillingsPrompt.textContent = 'Select ' + fillingsAllowed + ' fillings';
}
function getSelectedCount() {
var options = fillings.options, count = 0;
for (var i=0; i < options.length; i++) {
if (options[i].selected) count++;
}
return count;
}
function getSelectedValues() {
var options = fillings.options, values = [0];
for (var i=0; i < options.length; i++) {
if (options[i].selected) values.push(options[i].value);
}
return values;
}
function resetSelect() {
var options = fillings.options;
for (var i=0; i < options.length; i++) {
options[i].selected = false;
if (currentSelection.indexOf(options[i].value) != -1) {
options[i].selected = true;
}
}
}
fieldset {
margin: 1vw; font-family: monospace;
display: inline-block; width: 40vw; vertical-align: top;
}
legend { color: #d33; padding: 0px 4px; }
legend::before { content: '[ '; }
legend::after { content: ' ]'; }
fieldset > label { display: block; margin: 4px 0px; }
fieldset input, fieldset span { vertical-align: middle; }
fieldset > select { width: 100%; font-family: monospace; }
input[type=submit] { margin-top: 12px; }
#totalPrice, #result {
height: 24px; line-height: 24px;
background-color: #dde; padding: 4px;
font-family: monospace;
}
#result { color: #d33; font-family: monospace; }
<form action="" method="post" id="menuform" name="menuform">
<fieldset>
<legend>Select menu option</legend>
<label>
<input type="radio" name="selectedmenu" checked
value="menu01" data-qty='3' data-price='20' />
<span>1 - serves 3 courses ($20)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu02" data-qty='4' data-price='25' />
<span>2 - serves 4 courses ($25)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu03" data-qty='5' data-price='35' />
<span>3 - serves 5 courses ($35)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu04" data-qty='6' data-price='75' />
<span>4 - serves 6 courses ($75)</span>
</label>
</fieldset>
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<select id="fillings" name="fillings" size="6" multiple>
<option value="1">Dish 1 ($1)</option>
<option value="2">Dish 2 ($5)</option>
<option value="3">Dish 3 ($5)</option>
<option value="4">Dish 4 ($1)</option>
<option value="5">Dish 5 ($5)</option>
<option value="6">Dish 6 ($5)</option>
</select>
</fieldset>
<fieldset>
<legend>Checkout</legend>
<div id="totalPrice"></div>
<input type="submit" value="Submit" />
</fieldset>
<fieldset>
<legend>Messages</legend>
<p id="result"></p>
</fieldset>
</form>
<hr>
...how can I change
<option>
and use<input type="checkbox">
instead for the SECOND STEP?
In order to use checkboxes instead of select, no major changes are required.
Changed mark-up:
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<label>
<input type='checkbox' name='fillings' value="1" />
<span>Dish 1 ($5)</span>
</label>
...
JavaScript changes:
(just like the radios already done)
for (var i = fillings.length; i--; ) {
fillings[i].addEventListener('change', handleFillings);
}
(as it is now no longer required)
var options = fillings.options
And, In all the helper functions,
change: options.length
and options[i].selected
to, fillings.length
and fillings[i].checked
respectively.
That's it.
Fiddle 2: https://jsfiddle.net/abhitalks/hp88wdfc/
Snippet 2:
var menuform = document.getElementById('menuform'),
radios = document.getElementsByName('selectedmenu'),
fillings = document.getElementsByName('fillings'),
fillingsPrompt = document.getElementById('fillingsPrompt'),
totalPrice = document.getElementById('totalPrice'),
result = document.getElementById('result'),
fillingsAllowed = 0, currentSelection = [], currency = '$'
;
// listen to events
menuform.addEventListener('submit', handleSubmit);
for (var i = fillings.length; i--; ) {
fillings[i].addEventListener('change', handleFillings);
}
for (var i = radios.length; i--; ) {
radios[i].addEventListener('change', handleLimit);
}
// event handlers
function handleLimit(e) { updateParameters(e.target); }
function handleFillings(e) {
var count = getSelectedCount();
if (count > fillingsAllowed) { resetSelect(); }
else { currentSelection = getSelectedValues(); }
}
function handleSubmit(e) {
var count = getSelectedCount();
e.preventDefault();
if (count != fillingsAllowed) {
result.textContent = 'Must select exactly ' + fillingsAllowed + ' fillings!';
} else {
result.textContent = 'Ok. ';
}
}
// fire initial update based on the first radio
updateParameters(radios[0]);
// helper functions
function updateParameters(elem) {
fillingsAllowed = elem.getAttribute('data-qty');
totalPrice.textContent = 'Amount: ' + currency + elem.getAttribute('data-price');
fillingsPrompt.textContent = 'Select ' + fillingsAllowed + ' fillings';
}
function getSelectedCount() {
var count = 0;
for (var i=0; i < fillings.length; i++) {
if (fillings[i].checked) count++;
}
return count;
}
function getSelectedValues() {
var values = [0];
for (var i=0; i < fillings.length; i++) {
if (fillings[i].checked) values.push(fillings[i].value);
}
return values;
}
function resetSelect() {
for (var i=0; i < fillings.length; i++) {
fillings[i].checked = false;
if (currentSelection.indexOf(fillings[i].value) != -1) {
fillings[i].checked = true;
}
}
}
fieldset {
margin: 1vw; font-family: monospace;
display: inline-block; width: 40vw; vertical-align: top;
}
legend { color: #d33; padding: 0px 4px; }
legend::before { content: '[ '; }
legend::after { content: ' ]'; }
fieldset:first-of-type > label { display: block; margin: 4px 0px; }
fieldset:nth-of-type(2) > label {
display: inline-block; width: 45%;
}
fieldset input, fieldset span { vertical-align: middle; }
input[type=submit] { margin-top: 12px; }
#totalPrice, #result {
height: 24px; line-height: 24px;
background-color: #dde; padding: 4px;
font-family: monospace;
}
#result { color: #d33; font-family: monospace; }
<form action="" method="post" id="menuform" name="menuform">
<fieldset>
<legend>Select menu option</legend>
<label>
<input type="radio" name="selectedmenu" checked
value="menu01" data-qty='3' data-price='20' />
<span>1 - serves 3 courses ($20)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu02" data-qty='4' data-price='25' />
<span>2 - serves 4 courses ($25)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu03" data-qty='5' data-price='35' />
<span>3 - serves 5 courses ($35)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu04" data-qty='6' data-price='75' />
<span>4 - serves 6 courses ($75)</span>
</label>
</fieldset>
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<label>
<input type='checkbox' name='fillings' value="1" />
<span>Dish 1 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="2" />
<span>Dish 2 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="3" />
<span>Dish 3 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="4" />
<span>Dish 4 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="5" />
<span>Dish 5 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="6" />
<span>Dish 6 ($5)</span>
</label>
</fieldset>
<fieldset>
<legend>Checkout</legend>
<div id="totalPrice"></div>
<input type="submit" value="Submit" />
</fieldset>
<fieldset>
<legend>Messages</legend>
<p id="result"></p>
</fieldset>
</form>
<hr>