Reputation: 277
I'm making a pizza delivery website, each pizza comes in three sizes, each size has its own price. How can I write a code so that each pizza has its own price, and also the price differs depending on the size of one pizza with vanila javascript. In html I have two pizza models similar to each other, but they cost the same. In order not to clutter up the code and not make it readable, I added only one
<div class="card" >
<div class="productInCart">
<img src="/images/picca/4-seasons.png" width="250px" alt="">
<h3 class="title">Four seasons</h3>
<p class="description">
Bacon, Ham, Mushrooms, Chicken, Onion, Olives,
Pickled Cucumbers, Hunting sausages, Pepperoni
</p>
<div class="picca_size">
<label data-size="small" class="btnActive">20sm</label>
<label data-size="medium" class="btnActive">28sm</label>
<label data-size="large" class="btnActive">33sm</label>
</div>
<div class="wrapperPrice">
<p class="price">$<span>0</span></p>
<button class="button-30 addToCart" role="button" data-product-id="1">
add to cart
</button>
</div>
</div>
</div>
Javascript file
window.addEventListener( 'click', function(event){
// buttons for size picca and price
if (event.target.closest('.card')){
const cardWrapper = event.target.closest('.card')
const btnActiveSmall = cardWrapper.querySelector('[data-size="small"]')
const btnActiveMedium = cardWrapper.querySelector('[data-size="medium"]')
const btnActiveLarge = cardWrapper.querySelector('[data-size="large"]')
price = cardWrapper.querySelector('.price span')
if (event.target.className == 'btnActive'){
// active off buttons
btnActiveSmall.classList.remove('active')
btnActiveMedium.classList.remove('active')
btnActiveLarge.classList.remove('active')
if(event.target.dataset.size == "small"){
event.target.classList.add("active")
price.textContent = '12';
}
else if(event.target.dataset.size == 'medium'){
event.target.classList.add('active')
price.textContent = '16';
}
else if(event.target.dataset.size == 'large'){
event.target.classList.add('active')
price.textContent = '20';
}
}
Upvotes: 0
Views: 67
Reputation: 63524
Instead of hard-coding all the options in HTML it maybe easier to visualise and control if all the options were in a JavaScript structure that you can manipulate.
In this example there is an array of available pizzas along with their options (size, price). We can then create an order object from this list, adding a total
property.
Add the pizza HTML to the page, and update the totals as the user selects some options.
// Pizzas!
const pizzas = [
{
name: 'Four Seasons',
description: 'Bacon, Ham, Mushrooms, Chicken, Onion, Olives, Pickled Cucumbers, Hunting sausages, Pepperoni',
options: {
small: { size: '20', price: 12 },
medium: { size: '28', price: 16 },
large: { size: '33', price: 20 }
}
},
{
name: 'Chocolate and Spinach',
description: 'Chocolate, Spinach, Eye Of Newt, Ghost Pepper',
options: {
small: { size: '20', price: 22 },
medium: { size: '28', price: 26 },
large: { size: '33', price: 30 }
}
}
];
// Create an order by copying the pizzas to a `pizzas` property
// and adding a subtotal to each pizza, followed by a `total`
// property for the completed order
const order = {
pizzas: [...pizzas].map(pizza => {
return { ...pizza, total: 0 };
}),
total: 0
};
// For each pizza we return some HTML showing
// the name, description, and its options
const pizzasHtml = pizzas.map(pizza => {
const { name, description, options } = pizza;
return `
<h4>${name}</h4>
<p>${description}</p>
<div>${getOptions(options, name)}</div>
`;
});
// Creating some HTML for the options
function getOptions(options, name) {
return Object.entries(options).map(([type, option]) => {
const { size, price } = option;
return `
<div class="options">
<label>${type} (${size}cm)</label>
<input
class="quantity"
size="3"
type="number"
min="0"
data-type="${type}"
data-name="${name}"
data-price="${price}"
/>
$${price}
</div>
`;
}).join('<br />');
}
// Cache the important elements
const totalEl = document.querySelector('.total');
const pizzasEl = document.querySelector('.pizzas');
const submit = document.querySelector('.submit');
// Add the HTML to the page
pizzasEl.insertAdjacentHTML('beforeend', pizzasHtml.join(''));
// Add listeners to the submit button, and the pizzas element
submit.addEventListener('click', handleSubmit);
pizzasEl.addEventListener('change', handleChange);
// Remove any pizzas from the order for which an
// order has not been placed
function cleanOrder(order) {
return {
...order,
pizzas: order.pizzas.filter(pizza => pizza.total !== 0)
};
}
// Log the final JSON which will be sent to
// the server
function handleSubmit() {
console.log(JSON.stringify(cleanOrder(order)));
}
// Get a final total based on the pizza subtotals
function getTotal(order) {
return order.pizzas.reduce((acc, pizza) => {
acc += pizza.total;
return acc;
}, 0);
}
// When an input is changed update the order object
// and update the total
function handleChange(e) {
if (e.target.matches('.quantity')) {
const { dataset: { name, type }, value } = e.target;
const updatedOrder = updateOrder(order, name, value, type);
totalEl.textContent = `$${updatedOrder.total}`;
}
}
// Depending on what pizza has been updated calculate
// update its subtotal, and the order total
function updateOrder(order, name, value, type) {
const pizza = order.pizzas.find(pizza => pizza.name === name);
pizza.options[type].quantity = +value;
let total = 0;
for (const option in pizza.options) {
const { quantity, price } = pizza.options[option];
total += (quantity || 0) * price;
}
pizza.total = total;
order.total = getTotal(order);
return order;
}
.options { text-transform: capitalize; }
.options label { width: 120px; display: inline-block; }
.quantity { margin: 0 1em; }
.pizzas { margin-bottom: 1em; }
.summary, .submit { margin-top: 1em; }
<div class="pizzas"></div>
<hr />
<div class="summary">Total: <span class="total"></span></div>
<button class="submit">Submit order</button>
Upvotes: 1
Reputation: 43880
Use <form>
and form controls along with the methods and properties of the HTMLFormElement interface.
Details are commented in example
// Bind the input event to <form>
document.forms.pizza.oninput = calc;
// Event handler passes Event Object by default
function calc(e) {
// Reference all form controls
const IO = this.elements;
/*
Get the selected value of radio button group [name="size"] and convert
it into a float OR 0
*/
let size = parseFloat(IO.size.value) || 0;
/*
Get the value of each selected <option> and convert them into floats
reduce() the array down to the sum of selected values
*/
let meat = [...IO.meat.options].reduce((sum, add) => {
let value = add.selected ? add.value : 0;
return sum + parseFloat(value);
}, 0) || 0;
// Same as above
let vege = [...IO.vege.options].reduce((sum, add) => {
let value = add.selected ? add.value : 0;
return sum + parseFloat(value);
}, 0) || 0;
// The value of <output> is all 3 sub-totals
IO.total.value = (size + meat + vege).toFixed(2);
}
html {font: 300 2ch/1.2 'Segoe UI'}
form {display:flex;}
h1, h2 {margin:0;}
fieldset {width:max-content;margin-bottom:8px;}
label {display:inline-block;margin-bottom:8px;}
[type='radio'] {transform: translateY(1.5px)}
select {width:10rem;font:inherit;margin-bottom:8px;}
output::before {content:'$';}
.instructions {margin-left: 12px;float:right;transform:translateY(-100%)}
<h1>Fictional Pizza</h1>
<form id='pizza'>
<fieldset>
<legend><h2>Size</h2></legend>
<input id='lg' name='size' type='radio' value='20.25'>
<label for='lg'>Large 20.25</label><br>
<input id='md' name='size' type='radio' value='15.75'>
<label for='md'>Medium 15.75</label><br>
<input id='sm' name='size' type='radio' value='10.50'>
<label for='sm'>Small 10.50</label>
</fieldset>
<fieldset>
<legend><h2>Toppings</h2></legend>
<label for='meat'>Meat 1.00ea</label><br>
<select id='meat' multiple>
<option value='1.00'>Peperoni</option>
<option value='1.00'>Sausage</option>
<option value='1.00'>Linguisa</option>
<option value='1.00'>Hamburger</option>
<option value='1.00'>Canadian Bacon</option>
<option value='1.00'>Anchovies</option>
</select><br>
<label for='vege'>Vegetables .50ea</label><br>
<select id='vege' multiple>
<option value='.50'>Bell Pepper</option>
<option value='.50'>Pineapple</option>
<option value='.50'>Olives</option>
<option value='.50'>Onions</option>
<option value='.50'>Mushrooms</option>
<option value='.50'>Garlic</option>
</select>
<label class='instructions'>
Select multiple items<br>
Win click + <kbd>Ctrl</kbd><br>
Mac click + <kbd>⌘</kbd>
</label>
</fieldset>
<fieldset id='panel'>
<legend><h2>Total</h2></legend>
<output id='total'></output>
</fieldset>
</form>
Upvotes: 1