Calculate and Display % Discount for Price Classes JavaScript

Calculate discount % on a product in Vanilla JS

The problem can be found here;

var wasPrice = parseFloat(document.querySelector('.product-price__was').textContent.replace(pattern, "")) / 100;
var newPrice = parseFloat(document.querySelector('.product-price__discount').textContent.replace(pattern, "")) / 100;

You are using document.querySelector, however, you'll need the el element provided by the forEach like so:

var wasPrice = parseFloat(el.querySelector('.product-price__was').textContent.replace(pattern, "")) / 100;
var newPrice = parseFloat(el.querySelector('.product-price__discount').textContent.replace(pattern, "")) / 100;

Also, to prevent the length error, check if the querySelector has found anything by checking for null, instead off .length:

if (el.querySelector('.product-price__discount') !== null) {

Take a look at this improved example:

var pattern = /[^0-9\.]/g;
var price = document.querySelectorAll('.product-slab__price');

price.forEach(function(el){
if (el.querySelector('.product-price__discount') !== null) {
var wasPrice = parseFloat(el.querySelector('.product-price__was').textContent.replace(pattern, "")) / 100;
var newPrice = parseFloat(el.querySelector('.product-price__discount').textContent.replace(pattern, "")) / 100;

var discount = 100 - (newPrice / wasPrice) * 100;
el.querySelector('.discountPercentage').innerHTML = discount.toFixed(0) + "%";
}
});
.product-price__was {
text-decoration: line-through;
}
.product-price__discount {
color: red;
}
<div class="product-slab__price">
<div class="product-price__primary">
<span class="product-price__was">Was €10,00</span>
<span class="product-price__discount">Now €8,00</span>
<span class="discountPercentage" > </span>
</div>
</div>

<div class="product-slab__price">
<div class="product-price__primary">
<span class="product-price__was">€15,00</span>
<span class="product-price__discount">€10,00</span>
<span class="discountPercentage" > </span>
</div>
</div>


<div class="product-slab__price">
<div class="product-price__primary">
<span class="product-price__value">€15,90</span>
<span class="discountPercentage" > </span>
</div>
</div>

How to calculate discount for all products

Spans do not have onload

Perhaps you meant this

$(function() { // on page load
$(".discount").each(function() {
const price = +$(this).closest("div").find(".original").text();
const korting = (Math.round((price - ((price) / 100) * 10)));
$(this).text(korting)
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>
<div>$<span class="original">100</span>  $<span class="discount"></span></div>

Calculate percentage discount of multiple products on a product listing page

The issue is because you're selecting all the elements in the DOM with those classes as you iterate through the loop.

Instead, you need to target the elements with those classes relevant to the current .product-slab__price in the iteration. To do that use the this keyword and the find() method:

setTimeout(function discountPrice() {
var pattern = /[^0-9\.]/g;

$('.product-slab__price:has(.product-price__value--discounted)').each(function() {
let $slab = $(this);
var wasPrice = parseFloat($slab.find(".product-price__primary .product-price__was").text().replace(pattern, "")) / 100;
var newPrice = parseFloat($slab.find(".product-price__primary .product-price__value--discounted").text().replace(pattern, "") / 100);

var subtractPrice = Math.abs(wasPrice - newPrice);
var dividePrice = Math.abs(subtractPrice / wasPrice);
var multiplyPrice = Math.abs(dividePrice * 100);

$slab.find('.discountPercentage').html(multiplyPrice.toFixed(0) + "%");
});
}, 500);
.product-price__was {
text-decoration: line-through;
}

.product-price__value.product-price__value--discounted {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="product-slab__price">
<div class="product-price__primary">
<span class="product-price__was">Was €10,00</span>
<span class="product-price__value product-price__value--discounted">Now €8,00</span>
<span class="discountPercentage"> </span>
</div>
</div>

<div class="product-slab__price">
<div class="product-price__primary">
<span class="product-price__was">€15,00</span>
<span class="product-price__value product-price__value--discounted">€10,00</span>
<span class="discountPercentage"></span>
</div>
</div>


<div class="product-slab__price">
<div class="product-price__primary">
<span class="product-price__value">€15,90</span>
<span class="discountPercentage"></span>
</div>
</div>

How to calculate discount for each item of an array using reduce()?

While looping through the price items array, using reduce, you are already accessing each item element and calculating the discounted price for each item. So before updating the reduce accumulator update the item value.

Update each item and add to total:

// CHANGE:
// let totalValue = items.reduce((acc, cur) => acc + (1 - (numDiscount / 100)) * cur.innerText, 0);

// TO:
let totalValue = items.reduce((acc, cur) => {
let itemdisc = (1 - (numDiscount / 100)) * cur.innerText; // calculate item discount
cur.innerText = itemdisc; // update item
return acc + itemdisc; // update total
}, 0);

And prevent discount from being applied again:

document.querySelector('.total__button').disabled = true;

Updated script:

function getDomNodesBySelector(selector) {
return Array.from(document.querySelectorAll(selector));
}

document.querySelector('.total__button').addEventListener('click', applyDiscount);

function applyDiscount() {
let items = getDomNodesBySelector(".price-value");
let numDiscount = 15;
let totalValue = items.reduce((acc, cur) => {
let itemdisc = (1 - (numDiscount / 100)) * cur.innerText; // calculate item discount
cur.innerText = itemdisc; // update item
return acc + itemdisc; // update total
}, 0);
document.querySelector(".total-price-value").innerText = totalValue;

// prevent discount from being applied more than once
document.querySelector('.total__button').disabled = true;
}

Jquery discount calculation from range

For your example (elements of whole_sell_qty are sorted and values are evenly spaced out) you can get the index of the element in whole_sell_price like this:

let qty = $(".quantity").val();
let index = Math.floor( (qty-1)/10 );
if(index < 0) {
index = 0;
} else if(index > whole_sell_qty.length-1) {
index = whole_sell_qty.length - 1;
}

If the elements in whole_sell_qty were not spaced out evenly then you could make a function to figure out the correct price for the given quantity:

function setPrice() {
let qty = $(".quantity").val();
let length = whole_sell_qty.length;

for(let i=0; i < length; i++) {
if(qty > whole_sell_qty[i])
continue;

$("#total").text(qty * whole_sell_price[i]);
return;
}
$("#total").text(qty * whole_sell_price[length-1]);
}

Note: Both of these solutions assume your two arrays whole_sell_qty and whole_sell_price have matching elements in the same indexes. If that is not the case you could consider using an object to represent the different quantities and their respective prices.


Try it out:

Note: I added the min attribute to the input[type="number"] element so you can't click your way to a value less than 0. But you can still enter a negative number manually in the text field. For that I didn't provide a solution here but you can see how to deal with that here.

var whole_sell_qty = [10, 20, 30];
var whole_sell_price = [10, 9, 8];

$(".quantity").on('click', function () {
let qty = $(".quantity").val();
// this will get the correct price index for whole_sell_price based on qty
let index = Math.floor( (qty-1)/10 );

if(index < 0) {
index = 0;
} else if(index > whole_sell_qty.length-1) {
index = whole_sell_qty.length - 1;
}

$("#total").text(qty * whole_sell_price[index]);
});
table, th, td, tr {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>

<label>Product name : shoe</label><br>
<label>Product price : </label><input type="number" id="price" value="10" disabled><span>$</span><br>
<label>Qty : </label> <input type="number" name="quantity" min="0" class="quantity" value="0"/><br>
<label>Total : <span id="total">0</span></label>

<table>
<thead>
<tr>
<th>qty range</th>
<th>unit price</th>
</tr>
</thead>
<tbody>
<tr>
<td>1-10</td>
<td>$ 10</td>
</tr>
<tr>
<td>11-20</td>
<td>$ 9</td>
</tr>
<tr>
<td>21-30</td>
<td>$ 8</td>
</tr>
</tbody>
</table>


Related Topics



Leave a reply



Submit