Jquery price increase by slab - javascript

i am working on some project and I'm facing some issue
actually i want price increase by slap like i am allowing customer to select guest for booking for e.g the main price of product is 100 and additional price of guest is 50 and limit of guest is 4 when customer select 5 guest then the main price should be add in total price after when customer select 6 guest then only add 50 price i am sharing some code but its not working properly.
main price = 100
addintion price = 50
Guest
Price
1
100
2
150
3
200
4
250
5
350 add main price again (100)
6
400
7
450
8
500
9
600 add main price again (100)
10
650
group_size = 4;
increased_group_size = 4;
total_guests = me.guests;
if(total_guests<=group_size){
increased_group_size -= group_size;
if(increased_group_size==0){
increased_group_size += group_size;
}
}
if(total_guests>increased_group_size){
main_price = main_price;
increased_group_size += group_size;
final_price += main_price;
}
else{
final_price1 = total_guests * me.addtional_price;
}
total += final_price1 + final_price + me.price;
I tried the above code but not working properly.

Divide the number of additional guests by the group size. For each group, add the difference between the main price and additional price.
function calculate_price(total_guests) {
let additional_guests = total_guests - 1;
let group_size = 4;
let additional_groups = Math.floor(additional_guests / group_size);
let main_price = 100;
let additional_price = 50;
let total_price = main_price + additional_guests * additional_price + additional_groups * (main_price - additional_price);
return total_price;
}
for (let guests = 1; guests <= 10; guests++) {
console.log(`Guests = ${guests} Price = ${calculate_price(guests)}`);
}

Essentially what you need to do is check whether the current number is divisible by your max number. Then add one number if it is, and another number if it isn't.
Here's a working example.
const guestNum = $(".guests-total");
const total = $(".total");
$(".button").on("click", (e) => {
let numMult = 1;
const num = parseInt(guestNum.text());
let curTotal = parseInt(total.text());
let testNum = num + 1;
if (e.target.classList[1] === "min") {
numMult = -1;
testNum = num;
if (num === 0) {
return;
}
}
while (testNum > 0) {
testNum = testNum - 5;
}
if (testNum !== 0) {
curTotal += numMult * 50;
guestNum.text(num + numMult * 1);
total.text(curTotal);
return;
}
curTotal += numMult * 100;
guestNum.text(num + numMult * 1);
total.text(curTotal);
return;
});
.wrapper {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 5vw;
gap: 2vw;
}
.row-one {
display: flex;
justify-content: center;
align-items: center;
gap: 3vw;
}
.icon-test {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div class="wrapper">
<div class="row-one">
<div class="button min">-</div>
<div class="guests-total">0</div>
<div class="button add">+</div>
</div>
<div class="row-two">
<div class="money-total">Total: $<span class="total">0</span></div>
</div>
</div>
</body>
</html>
Let's break this down.
Here we get the DOM elements for the number of guests and the sub-total of money.
const guestNum = $(".guests-total");
const total = $(".total");
Then we register an event listener for a click on the button to either add or subtract a guest.
$(".button").on("click", (e) => {
I set a variable called numMult that I will multiply all my sub-total numbers by to either subtract or add money (I'll explain that more later).
let numMult = 1;
Then I get the actual text contained in the DOM elements and convert those to integers so we can add or subtract from them.
const num = parseInt(guestNum.text());
let curTotal = parseInt(total.text());
Finally I make a new variable that will be used to test if the current number is a multiple of 5 or not.
let testNum = num + 1;
Here we check if the button that was clicked is the subtract button or the add button, if it's the subtract button then we will be multiplying all our numbers by -1 so that it subtracts from the subtotal instead of adds to it.
If the current number is 0 we return because there obviously can't be negative guests.
if (e.target.classList[1] === "min") {
numMult = -1;
testNum = num;
if (num === 0) {
return;
}
}
Here we subtract from the total number of guests until num is less than or equal to zero.
while (testNum > 0) {
testNum = testNum - 5;
}
If our test number doesn't come out as zero, we know that the number isn't 5 or divisible by 5, so we add or subtract 50.
if (testNum !== 0) {
curTotal += numMult * 50;
guestNum.text(num + numMult * 1);
total.text(curTotal);
return;
}
Otherwise, if our test number is 0, we know that the number of guests is either 5 or a multiple of 5, so we add 100.
curTotal += numMult * 100;
guestNum.text(num + numMult * 1);
total.text(curTotal);
return;
I hope this helps out.

Related

Incrementing and padding in Javascript

I'm trying to write an app that allows a user to increment a series of numbers. When I let i = 1, all is well and my sequence output is perfect. Unfortunately, the series will rarely start with 1, it will start with a user defined number. And that's where I'm getting hung up:
const totalEl = document.querySelector('#total');
const perEl = document.querySelector('#per');
const numEl = document.querySelector('#num');
const calculateEl = document.querySelector('#calculate');
const outputEl = document.querySelector('#output');
calculateEl.addEventListener('click', onCalculateButtonClick);
function onCalculateButtonClick() {
const total = Number(totalEl.value);
const numPerRoll = Number(perEl.value);
const num = Number(numEl.value);
const numPerBatch = numPerRoll * 2;
const batches = Math.ceil(total / numPerBatch);
let output = `Total batches: ${batches}\nTotal rolls: ${batches * 2}\n\n`;
for (let i = 1; i <= batches; i++) {
output += `Batch ${i}A -- ${(numPerBatch * (i - 1)) + 1}-${(numPerBatch * (i - 1)) + numPerRoll}\n`;
output += `Batch ${i}B -- ${(numPerBatch * (i - 1)) + numPerRoll + 1}-${numPerBatch * i}\n`;
}
outputEl.innerText = output;
}
body {
font-family: system-ui;
background: linear-gradient(to bottom, azure, #a4ffff);
color: black;
height: 100vh;
margin: 0;
display: grid;
}
<h1 style="text-align: center;">πŸ‘‹ Generator 0.1 πŸ‘‹</h1>
<p style="text-align: center;">Please enter your values in the dashboard<br> Note: in order to print a complete 2-up batch, the order may be rounded up</p>
<div><label>Order total <input id="total" value="50000"/></label></div>
<div><label>Total per sequence <input id="per" value="1500"/></label></div>
<div><label>Starting number <input id="num" value="1"/></label></div>
<div><label>Prefix <input id="prefix" value="ABC"/></label></div>
<div><button id="calculate">Calculate</button></div>
<br/>
<div id="output"></div>
How do I let i = a user defined number? I'm missing something fundamentally obvious here.
I also need to turn this number into a string (I think) and pad it out to 8 digits... I've tried adding something like this in with lots of hilarity, hair pulling and no results:
let num = i;
let text = num.toString();
let padded = text.padStart(8,"0");
I think what I tried was something like this:
for (let i = num; i <= batches; text = num.toString(); padded = text.padStart(8,"0"); {
I've got a kind of working version of this at codepen:
https://codepen.io/swartzfeger/pen/yLjgEpK
More in-depth dump of what I'm trying to accomplish
TL;DR What I need: generate a series of UPC codes that are incremented and split into batches.
Let's say our customer wants 10,000 UPCs, with 1000 UPCs per roll (these are being printed on film and wound onto rolls).
That would be a total of 10 rolls. But each 2x 1000 sequence can be printed at once, printing 2 up. So there are a total of 5 print batches.
That's not the hard part since the example is cut and dried. Most client jobs vary greatly, and we often have to print extra so we're not wasting film -- ie, we always want a full batch and not printing just 1 up for the batch. A partial batch would leave us with 1 roll of empty non-printed film.
ie, an order of 50,000 total, 1500 per sequence. 50k / 3000 per batch leaves us with 16.66 batches. So we would want to round that up to 17. So we would want to bump the print total to 51k (17 x 3000 = 51,000.
What I need to do is create a dashboard where the operator enters the job total (50,000) and the total per sequence (1500). The dashboard would then spit out you're running a job total of 51,000, 17 batches/34 rolls total. It would then give the operator the print breakdown --
Batch 1A -- 0000-1500
Batch 1B -- 1501-3000
Batch 2A -- 3001-4500
Batch 2B -- 4501-6000 etc
HOWEVER -- we would rarely begin a sequence with i =1 -- we would be picking up from where our last job ended, so the user would enter the new beginning sequence number. So I wouldn't be incrementing from 0 or 1, but an arbitrary number like 6293.
AND -- these numbers are of going to be a fixed length (usually 8 digits). So a starting sequence number of 6293 would have to be padded out to 00006293.
Make a small utility function like so:
const z = (number, size) => number.toString().padStart(size, "0");
Then assign some variables to the function's returns and then interpolate those variables into the template literals like so:
let A1 = z(AB, 8);
let A2 = z(AB + (now / 2) - 1, 8);
let B1 = z(AB + (now / 2), 8);
let B2 = z(AB + now - 1, 8);
output += `Batch ${z(i + 1, 2)}A -- ${A1}-${A2}\n`;
output += `Batch ${z(i + 1, 2)}B -- ${B1}-${B2}\n`;
I removed the for loop and added .reduce().
Details are commented in example
const genForm = document.forms.generator;
const fc = genForm.elements;
const totalFC = fc.total;
const perFC = fc.per;
const numFC = fc.num;
const outputFC = fc.output;
// Utility function for padding zeros
const z = (number, size) => number.toString().padStart(size, "0");
genForm.addEventListener('submit', onCalculate);
function onCalculate(e) {
e.preventDefault();
const total = Number(totalFC.value);
const numPerRoll = Number(perFC.value);
const init = Number(numFC.value);
const numPerBatch = numPerRoll * 2;
const batches = Math.ceil(total / numPerBatch);
let output = `Total batches: ${batches}\nTotal rolls: ${batches*2}\n\n`;
// Generate an array of batches
const totalBatches = [...new Array(batches)].fill(numPerBatch);
/**
* On each iteration of totalBatches by .reduce()...
* >AB< is the accumulator, it will keep track of it's own value
* >now< is the current value (>numPerBatch<)
* >AB< starts as >init<, defaulting to 1
* >A1< - >A2< is >numPerRoll<
* >B1< - >B2< is >numPerRoll<
* >output< is rendered to display ranges A and B
* >now< is added to >AB<
* The returned value isn't used but needs to be defined so
* that the accumulator returns on the next iteration increased
*/
const final = totalBatches.reduce((AB, now, idx) => {
let A1 = z(AB, 8);
let A2 = z(AB + (now / 2) - 1, 8);
let B1 = z(AB + (now / 2), 8);
let B2 = z(AB + now - 1, 8);
output += `Batch ${z(idx + 1, 2)}A -- ${A1}-${A2}\n`;
output += `Batch ${z(idx + 1, 2)}B -- ${B1}-${B2}\n`;
return AB + now;
}, init);
outputFC.innerText = output;
}
html {
font: 300 2ch/1.15 'Segoe UI'
}
body {
min-height: 100vh;
margin: 0 auto;
background: linear-gradient(to bottom, azure, #a4ffff);
}
form {
display: flex;
justify-content: center;
align-items: center;
padding-top: 20px;
}
fieldset {
position: relative;
width: min(70vw, 500px);
}
input,
button {
font: inherit;
}
input {
width: 12rem;
}
button {
position: absolute;
right: 30px;
cursor: pointer;
}
label {
display: flex;
justify-content: space-between;
margin: 0 20px 15px 0;
}
label sup {
align-self: flex-start;
}
legend {
font-size: 1.5rem;
}
legend b,
[type="number"],
output {
font-family: Consolas;
}
[type="number"] {
text-align: right;
}
.note {
margin-left: 0.5ch;
font-size: 0.75rem;
text-indent: -1ch;
}
sup {
color: tomato
}
<form id="generator">
<fieldset>
<legend><b>βšβ˜β˜β™β¦€</b>Generator <b>0.1βšβ¦€β¦€βˆ₯β™β™β˜β˜β˜β¦€βˆ₯</b></legend>
<p>Please enter your values in the dashboard</p>
<label><span>Order total<sup>⚝</sup></span> <input id="total" type="number" value="50000"/>
</label>
<label>Total per sequence <input id="per" type="number" value="1500"/></label>
<label>Starting number <input id="num" type="number" value="1"/></label>
<label>Prefix <input id="prefix" placeholder="ABC"/></label>
<button>Calculate</button>
<p class='note'><sup>⚝</sup>Note: in order to print a complete 2-up batch, <br>the order may be rounded up.</p>
<output id="output"></output>
</fieldset>
</form>
The const z utility #zer00ne added cleaned things up for padding the digits
const z = (number, size) => number.toString().padStart(size, "0");
The user defined number sets the starting number of the sequence, and size determines the length in digits of the sequence. The "0" determines what the sequence will be padded with to reach the required final length.
ex, the user defines '123' as the starting the number of the sequence; const z turns this into '00000123' (an 8-digit sequence)
Defining the value >now< for the accumulator/iteration made things work flawlessly.
By using AB + now, the batches were able to increment properly:
// Generate an array of batches
const totalBatches = [...new Array(batches)].fill(numPerBatch);
// * On each iteration of totalBatches by .reduce()...
// * >AB< is the accumulator, it will keep track of it's own value
// * >now< is the current value (>numPerBatch<)
// * >AB< starts as >init<, defaulting to 1
// * >A1< - >A2< is >numPerRoll<
// * >B1< - >B2< is >numPerRoll<
// * >output< is rendered to display ranges A and B
// * >now< is added to >AB<
// * The returned value isn't used but needs to be defined so
// * that the accumulator returns on the next iteration increased
const final = totalBatches.reduce((AB, now, idx) => {
let A1 = z(AB, 8);
let A2 = z(AB + now / 2 - 1, 8);
let B1 = z(AB + now / 2, 8);
let B2 = z(AB + now - 1, 8);
and for the final output:
output += `Batch ${z(idx + 1, 2)}A | ${prefix} ${A1} - ${prefix} ${A2}\n`;
output += `Batch ${z(idx + 1, 2)}B | ${prefix} ${B1} - ${prefix} ${B2}\n`;
return AB + now;
}, init);
outputEl.innerText = output;
}

HTML Javascript loop to create a table

I need to create a table with html javascript which has the number of cells that are equal to the user input.
Basically, at the start, the user is prompted to enter a number and then a table is created that has number of cells which are equal to the user input number.
The number of columns should be 10.
The tricky part is to get the number of rows.
For example, if the user enters 30, then the table has 10 columns and 3 rows.
The problem comes, if the number is not a multiple of 10.
For example, if the user enters 32, with the code I created I can still get only 10 columns and 3 rows, which is still 30 cells.
In addition, I need to number the cells as well.
Can anyone help me out of this mess?
A picture of the table I need
<html>
<head>
<style>
table{width: 70%;}
</style>
<script>
let num= window.prompt("What is the loop maximum.? (between 1 and 500)")
if(num<0 || num>500)
{
window.alert("Warning! Must be between 1 and 500. Setting to default
100")
}
</script>
</head>
<body>
<h1>Javascript Loops and Functions</h1><br>
<script>
document.write("<table border=1>")
for (row=1; row<=num/10; row++) {
document.write("<tr>")
for (col=1; col<=10; col++) {
document.write("<td>"+ num + "</td>")
}
document.write("</tr>")
}
document.write("</table>")
</script>
</body>
Problem Description
We need a way to create a table of numbers starting at 0 till the last number provided to us by the user.
The last number must be between 1 and 500. (You can adjust the range as per your need.)
Solution Implemented in above code:
Columns - 10, Number = 30, Rows = (num / columns = 3)
Problems faced in above code:
Columns - 10, Number = 32, Rows = (num / columns = 3)
The no of rows is still 3, but we need atleast 4 rows to accomodate 32 numbers in 10 columns.
Data in each column printed is 32 if you enter 32 via prompt.
Visual Representation?
To understand the problem in our proposed solution, let us write what's happening under the hood.
Num / columns = No_of_Rows
30 / 10 = 3.0
31 / 10 = 3.1
32 / 10 = 3.2
33 / 10 = 3.3
34 / 10 = 3.4
35 / 10 = 3.5
36 / 10 = 3.6
37 / 10 = 3.7
38 / 10 = 3.8
39 / 10 = 3.9
40 / 10 = 4.0
300 / 10 = 30.0
301 / 10 = 30.1
...
This calculation provides us a hint that if our formula to compute no of rows is incorrect. The error occurs due to remainder in our code.
If we could somehow use this remainder to caluclate no of rows, then issue should be fixed.
What if we could increment no of rows by 1 if remainder is greater than 0 but less than 10? I think you got the point.
Now, It's time to modify our code to consider remainder.
// Read it as: if num modulo 10 is greater than 0 and less then 10 then increment row by 1 else don't
let rows = ((num % 10) > 0 && (num % 10) < 10) ? (num / 10) + 1 : num / 10;
So, replacing our no of rows by above code should fix the issue.
Solution 1
Here is complete code with issue fixed:
<html>
<head>
<style>
table {
width: 70%;
}
</style>
<script>
let num = window.prompt("What is the loop maximum.? (between 1 and 500)");
if (num < 0 || num > 500) {
window.alert(
"Warning! Must be between 1 and 500. Setting to default 100"
);
}
</script>
</head>
<body>
<h1>Javascript Loops and Functions</h1>
<br />
<script>
document.write("<table border=1>");
let rows = num % 10 > 0 && num % 10 < 10 ? num / 10 + 1 : num / 10;
for (row = 1; row <= rows; row++) {
document.write("<tr>");
for (col = 1; col <= 10; col++) {
document.write("<td>" + num + "</td>");
}
document.write("</tr>");
}
document.write("</table>");
</script>
</body>
</html>
Final Solution
Fix problem of printing same no in all columns:
Fix problem of printing nos in all 10 columns when not required(in case of 32)
<html>
<head>
<style>
table {
width: 70%;
}
</style>
<script>
let num = window.prompt("What is the loop maximum.? (between 1 and 500)");
if (num < 0 || num > 500) {
window.alert(
"Warning! Must be between 1 and 500. Setting to default 100"
);
}
</script>
</head>
<body>
<h1>Javascript Loops and Functions</h1>
<br />
<script>
document.write("<table border=1>");
// Formula to calculate no of rows.
let rows = num % 10 > 0 && num % 10 < 10 ? num / 10 + 1 : num / 10;
let count = 0; // Variable to keep track of numbers printed till now.
for (row = 1; row <= rows; row++) {
document.write("<tr>");
for (let i = 1; i <= 10; i++) {
if (count >= num) break; // Exit early if we already printed nos in less than 10 columns.
document.write("<td>" + count + "</td>");
count++;
}
document.write("</tr>");
}
document.write("</table>");
</script>
</body>
</html>
In this case you don't need a number of rows. You only need to trigger adding <td> elements into <tr> if cellNumber % columns === 0 inside your loop.
You forgot about:
number that you got from window.prompt ... is in fact a string - you have to convert it to an integer with parseInt()
set that default value to 100 as you mentioned in the alert ^^
I must also mention that using document.write() is considered to be a bad practise. It's better to use document.createElement() to create DOM elements and parentElement.appendChild(element) to insert DOM elements into another DOM elements.
With using document.write() you also limit yourself to adding elements into <body>. Handling with DOM elements gives you more possibilities - with them you can put such structures anywhere you want.
Here's a code snippet of a function which generates such table as a DOM element.
const generateTable = (cells, columns = 10) => {
const table = document.createElement('table');
let row = document.createElement('tr');
for(let i = 1; i <= cells; ++i){
const cell = document.createElement('td');
cell.textContent = i - 1;
row.appendChild(cell);
if(i % columns === 0 || i === cells){
table.appendChild(row);
row = document.createElement('tr');
}
}
return table;
};
You can pin a result of such function for example to body DOM element just like in an example below:
const table = generateTable(123, 12);
document.body.appendChild(table);
Here's my snippet matching it all together with all mentioned cases implemented:
const generateTable = (cells, columns = 10) => {
const table = document.createElement('table');
let row = document.createElement('tr');
for(let i = 1; i <= cells; ++i){
const cell = document.createElement('td');
cell.textContent = i - 1;
row.appendChild(cell);
if(i % columns === 0 || i === cells){
table.appendChild(row);
row = document.createElement('tr');
}
}
return table;
};
window.addEventListener("DOMContentLoaded", () => {
const numString = window.prompt("What is the loop maximum.? (between 1 and 500)");
let num = parseInt(numString);
if (num < 0 || num > 500) {
window.alert("Warning! Must be between 1 and 500. Setting to default 100");
num = 100;
}
const table = generateTable(num);
document.body.appendChild(table);
})
*{
box-sizing: border-box;
margin: 0;
padding: 0;
}
table{
border-collapse: collapse;
}
td{
text-align: center;
padding: 7px 14px;
border: 1px grey solid;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Table loop example</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<script src="script.js"></script>
</body>
</html>
Docs reference:
https://developer.mozilla.org/pl/docs/Web/API/Node/appendChild - appending child to parent
https://developer.mozilla.org/pl/docs/Web/API/Document/createElement - creating a DOM element
https://developer.mozilla.org/pl/docs/Web/API/Element - some knowledge about DOM elements
https://developer.mozilla.org/pl/docs/Web/JavaScript/Reference/Global_Objects/parseInt - parseInt()
function generateTable(n, columnCount=10) {
document.write("<table border=1>");
document.write("<tr>");
for (i = 0; i < n; i++) {
if (i % columnCount === 0) {
document.write("</tr>");
document.write("<tr>");
}
document.write("<td>" + i + "</td>");
}
document.write("</tr>");
document.write("</table>");
}
That should work for you ^^

Javascript Greedy Algorithm Making Change

I'm working on the classic "making change" problem, which is highly documented in plenty of other languages, but there's not much out there for it in Javascript. So far, I have this:
var total = $('#total').val();
var coins = [];
function makeChange(total, coins) {
var remainder = 0;
if (total % 0.25 < total) {
coins[3] = parseInt(total / 0.25);
remainder = total % 0.25;
total = remainder;
}
if (total % 0.10 < total) {
coins[2] = parseInt(total / 0.10);
remainder = total % 0.10;
total = remainder;
}
if (total % 0.05 < total) {
coins[1] = parseInt(total / 0.05);
remainder = total % 0.05;
total = remainder;
}
coins[0] = parseInt(total / 0.01);
}
function showChange(coins) {
if (coins[3] > 0) {
$('.quarter').html(coins[3] + " quarter(s).");
}
if (coins[2] > 0) {
$('.dime').html(coins[2] + " dime(s).");
}
if (coins[1] > 0) {
$('.nickel').html(coins[1] + " nickel(s).");
}
if (coins[0] > 0) {
$('.penny').html(coins[0] + " pennies.");
}
}
makeChange(total, coins);
showChange(coins);
However, this seems awfully repetitive and I'm finding that with certain values, it's a penny off. How can I make it more accurate and concise?
I'm finding that with certain values, it's a penny off.
Probably due to floating-point issues. And you shouldn't use parseInt to convert a number - it's meant for strings.
this seems awfully repetitive
A loop, with a data structure that represent the different coins will help. You already did something like that for your result: coins is an array, not 4 different variables.
function makeChange(total, values) {
var coins = [],
epsilon = 1e-5; // this is wrong in general!
// assume values are ascending, so we loop backwards
for (var i=values.length; i--; ) {
coins[i] = Math.floor(total / values[i].val + epsilon);
total %= values[i].val;
}
return coins;
}
function showChange(coins, values) {
for (var i=values.length; i--; ) {
var el = $(values[i].sel);
if (coins[i] > 0) {
el.html(coins[i] + " "+values[i].name+".");
} else {
el.empty();
}
}
}
var values = [
{val:0.01, sel:'.penny', name:"pennies"},
{val:0.05, sel:'.nickel', name:"nickel(s)"},
{val:0.10, sel:'.dime', name:"dime(s)"},
{val:0.25, sel:'.quarter', name:"quarter(s)"}
];
showChange(makeChange(parseFloat($('#total').val()), values), values);
Your best bet to avoid rounding problems is to just multiple your total by 100 to convert your dollar amount into all pennies, then do you conversion. For example:
function makeChange(total, coins) {
var remainder = 0;
total = Math.round(total * 100);
coins[3] = Math.floor(total / 25);
remainder = total - coins[3] * 25;
total = remainder;
coins[2] = Math.floor(total / 10);
remainder = total - coins[2] * 10;
total = remainder;
coins[1] = Math.floor(total / 5);
remainder = total - coins[1] * 5;
total = remainder;
coins[0] = total;
}
http://jsfiddle.net/t14cwdph/4/
For making your code easier to manage - see #Bergi's answer.

Javascript and Variable assistance

(Rephrasing question from earlier) So here is the assignment:
First, you will have to calculate a cost for the weight of the parcel. The user will enter the total weight of their parcel into the text field. The schedule is as follows…
0 – 150 lbs $20.00 per pound
| 151 – 300 lbs $15.00 per pound
| 301 – 400 lbs $10.00 per pound
Do not allow the user to enter a weight that is < 0 or > 400. If they do, output an error message in red to div#results and β€˜return’ out of the function.
Next, the user will choose a discount amount (for whatever reason, does not matter). You will need to apply whatever discount amount is chosen. (50% off, 20% off, none).
This is what I have done so far. Variable aren't declared yet, just wrote them in.
function calcTotal() {
var msg;
var weight = parseInt( document.getElementById("weight").value );
var discount;
var total;
if( weight >= 0 && weight <= 150 ) {
total = weight * 20
}
else if( weight >150 && weight <= 300 ) {
total = weight * 15
}
else if( weight >300 && weight <= 400 ) {
total = weight * 10
}
if( document.getElementById("50%").selected == true ) {
total = total * 0.50;
}
if( document.getElementById("25%").selected == true ) {
total = total * 0.25;
}
if( document.getElementById("none").selected == true ) {
total = total;
}
Is this somewhat correct so far?
Can't seem to figure out how to apply the discount based on what the user selects. The discounts are 3 radio buttons. Do i need to apply an id to each radio button?
First of all you need to use && (AND) instead of || (OR) because you want both conditions to be met not just one. First IF statement will process value -1000 as TRUE (as well as any other value because your interval is from 0 to infinity plus from minus infinity to 150) because it satisfies the second part of the first condition.
Second, the formula is correct but you have to convert percents into 0-1 interval. 100% = 1, 0% = 0 and x% = x/100. Then it should work without any problems.
Last thing to do is that you need to pass the values into your function:
function calcTotal(weight, discount) {
// do the calculation with passed values, you do not need to declare them here anymore
}
Or you need to set values right inside of that function, e.g.:
function calcTotal() {
var discount = $("#inputField").val(); // using jQuery, where inputField is element
// from which the value is taken e.g. < input >
...
}
To display the final output, add this to your function:
$("body").append("<div id='output'>" + output + "</div>"); // using jQuery, watch for single/double quotes
and style it with css to be in the center:
#output {
position: absolute;
width: 200px;
height: 200px;
left: 50%;
margin-left: -100px;
top: 200px;
}
I made a fiddle that you should be able to get what is going on pretty quickly.
http://jsfiddle.net/a58rR/3/
I used a touch of jQuery just to get the bindings on the UI elements.
I hope this is not for a class and you copy this wholesale! ;)
Basically, I put all your Tier pricing into one object.
Tiers = [{
nPrice: 20,
nWeightMin: 1,
nWeightMax: 150
}, {
nPrice: 15,
nWeightMin: 151,
nWeightMax: 300
}, {
nPrice: 10,
nWeightMin: 301,
nWeightMax: 400
}];
Then, your function will calculate based on the entered weight and discount selected, determine the Tier, validate the weight, update the UI with a message if out of range, calculate the final price and apply any discount, and update the UI with the total price:
function calculatePrice() {
console.log('Begin Calc');
var _nW = document.getElementById('nParcelWeight').value * 1;
var _nD = document.getElementById('aDiscounts').value * 1;
var _nP = 0;
var nTotalPrice = 0;
var _TotalPrice = document.getElementById('nPrice');
var _nMaxWt = Tiers[Tiers.length - 1].nWeightMax;
// Using the last Tier keeps the max weight dynamic no matter how many tiers you add as long as they are in order
console.log('Max Weight: ' + _nMaxWt);
console.log('Weight: ' + _nW);
console.log('Discount: ' + _nD);
if (isNaN(_nW) || _nW < 1 || _nW > _nMaxWt) {
// Throw/Display an out of range error here
console.log('Yep, out of range');
document.getElementById('uiFeedback').innerHTML = 'The number is out of range.';
} else {
// reset if valid
document.getElementById('uiFeedback').innerHTML = '';
}
// Find Tier
for (var i = 0; i < Tiers.length; i++) {
console.log('we are in loop:' + i);
if (_nW >= Tiers[i].nWeightMin && _nW <= Tiers[i].nWeightMax) {
_nP = Tiers[i].nPrice;
break;
}
}
console.log('Tier: ' + i);
console.log('Price: ' + _nP);
// Calculate Discount
if (_nD != 1) _nD = 1 - _nD; // (20%==.20, but that would be .80 of the Price, etc)
// Calc Price
nTotalPrice = (_nP * _nW * _nD);
_TotalPrice.value = nTotalPrice;
}
The html will look something like this:
<div id='uiFeedback'></div>Parcel Weight:
<input id='nParcelWeight' value='0'>Discount:
<select id='aDiscounts'>
<option value='1'>none</option>
<option value='.2'>20%</option>
<option value='.5'>50%</option>
</select>
<hr>Price:
<input id='nPrice'>
And your CSS at a minimum might just color your messaging:
#uiFeedback {
color: red;
font-weight: bold;
}
Here are the bindings, which you could do with inline onChanges or raw js attach events:
$(function () {
$('#nParcelWeight,#aDiscounts ').on('change', function () {
calculatePrice();
});
})

image based count down clock

I have a count down clock which works absolutely fine. Now the question is can I display images as digits instead of html. I cant seem to figure out the logic how would I approach it. I really dont want to use a plugin for this so that is really not an option.
and the JS for the clock is this
setInterval(function(){
var future = new Date("Jan 20 2014 21:15:00 GMT+0200");
var now = new Date();
var difference = Math.floor((future.getTime() - now.getTime()) / 1000);
var seconds = fixIntegers(difference % 60);
difference = Math.floor(difference / 60);
var minutes = fixIntegers(difference % 60);
difference = Math.floor(difference / 60);
var hours = fixIntegers(difference % 24);
difference = Math.floor(difference / 24);
var days = difference;
$(".seconds").text(seconds + "s");
$(".minutes").text(minutes + "m");
$(".hours").text(hours + "h");
$(".days").text(days + "d");
}, 1000);
function fixIntegers(integer)
{
if (integer < 0)
integer = 0;
if (integer < 10)
return "0" + integer;
return "" + integer;
}
I have stored the images in an array which is this
var linkCons = 'http://soumghosh.com/otherProjects/Numbers/'
var num = [];
var linkCons = "http://soumghosh.com/otherProjects/Numbers/";
for(var i = 0; i < 10; i++) {
num.push(linkCons + "nw" + i + ".png");
}
Thanks to stack overflow folks helping me cleaning the array. Really appriciate it
And here is the working fiddle
http://jsfiddle.net/sghoush1/wvbPq/3/
You can do it using only one sprite image and this bit of code I created:
jQuery(function($) { // DOM ready shorthand
// CLOCK
// Just a date in the future... Say 5 days from now
var fut = new Date().setDate(new Date().getDate() + 5);
// Number splitter
function intSpl(i) {
i = Math.floor(i);
return [Math.floor(i / 10), i % 10]; // 37=[3,7] // 5=[0,5] // 0=[0,0]
}
var obj = {}; // {d:[7,7], h:[1,9], .....}
function drawTime() {
var now = new Date().getTime();
var dif = now < fut ? Math.floor((fut - now) / 1000) : 0;
obj.s = intSpl(dif % 60);
obj.m = intSpl(dif / 60 % 60);
obj.h = intSpl(dif / 60 / 60 % 24);
obj.d = intSpl(dif / 60 / 60 / 24);
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
for (var i = 0; i < 2; i++) { // get el ID number (0,1)
$('#' + key + i).css({
backgroundPosition: -obj[key][i] * 50
});
}
}
}
}
drawTime();
setInterval(drawTime, 1000);
});
#clock span {
display: inline-block;
width: 50px;
height: 85px;
background: url('http://i.imgur.com/uBTxTTD.jpg');
background-position: 0 0;
}
#clock span:nth-child(even) {
margin-right: 15px;
}
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<div id="clock">
<span id="d0"></span>
<span id="d1"></span>
<span id="h0"></span>
<span id="h1"></span>
<span id="m0"></span>
<span id="m1"></span>
<span id="s0"></span>
<span id="s1"></span>
</div>
To explain the idea:
Create elements, each will hold a one digit of the current 2 digits value;
Set a common bg image to all spans in CSS
Every second move each element's background-image left by -(witdh * number) px
While the listed above seems logic, the first problem you can see here is how to retrieve separately a JS time number (1 or 2 digits) keep leading zero if needed, and reference each digit to target the right element in HTML?
Let's start by splitting numbers:
35 == 3, 5 /// 0 == 0, 0 // this is an example of what we need.
var n = 35; // Set any 1 or 2 digit number.
var n1 = ~~(n/10); // 3 //// ~~ "Double Bitwise NOT"
// just instead of parseInt(time/10, 10).
var n2 = n%10; // 5 //// % "Mudulus operator" (reminder).
Example playground
JS Grouping
Now, how to group this two separated digits and say: "Hey you two are for my clock seconds!" ?
By simply putting them into an array! [3, 5], and for we'll have also minutes, hours and day - let's simply put all those arrays into an Object and assign a Key Name which will result in having an object like:
obj = {d:[7,4], h:[1,9], m:[2,9], s:[0,7]}
Reference to HTML
Having that Object and knowing that inside an for...in loop we can retrieve the Key name and the array value like eg: obj['d'][0] === 7 obj['d'][5] === 4
means that we'll need a for loop to retrieve the 0 and 1 to get the values in our array positions [pos0, pos1]
all inside a for...in loop that will get the KEY names : d, h, m, s
2pos x 4keyNames = 8 elements iterations/second
means that now we'll be able to target an ID element eg: #s0 and #s1
and all we need now is to retrieve the value and animate that element background by
-width * digit
Well, there's another way that you may use to solve the same problem. Here are the steps. Firstly I wrote one CSS class selector for each image position.
.list-group-item .digit-display{
display:inline-block;
width:50px;
height:85px;
background:url('http://i.imgur.com/uBTxTTD.jpg');
}
.position-0 {
background-position: 0 0;
}
.position-1 {
background-position: -50px 0px !important;
}
Then I wrote a JavaScript function which takes a digit as an input and return the CSS class selector for that digit as below.
displayDigit(digit) {
const baseSelector = "digit-display position-";
return `${baseSelector}${digit}`;
}
Finally this function is called inside the JSX element as below.
<span className = {this.displayDigit(remainingTime["h"].charAt(0))}></span>
That solved the issue.
However, if someone really needs to go with the jquery based approach specified above, we can still condense down that same code as below.
secondsToTime(secs) {
let hours = `${constants.ZERO}${Math.floor(secs / (60 * 60))}`.slice(-2);
let divisorForMinutes = secs % (60 * 60);
let minutes = `${constants.ZERO}${Math.floor(divisorForMinutes / 60)}`.slice(-2);
let divisorForSeconds = divisorForMinutes % 60;
let seconds = `${constants.ZERO}${Math.ceil(divisorForSeconds)}`.slice(-2);
let obj = {
"h": hours,
"m": minutes,
"s": seconds
};
return obj;
}
handleFlipClockImage = () => {
var myObj = this.secondsToTime(seconds);
Object.keys(myObj).forEach(key => {
let obj = myObj[key];
var digits = obj.split(constants.EMPTY_SPACE_CHAR);
digits.forEach((digit, index) => {
jquery(`#${this.state.label}${key}${index}`).css({backgroundPosition: -digit*50 });
});
});
}

Categories