newbie javascript tip calculator issues - javascript

So im only just really starting out on my javascript journey. I'm only just getting into DOM manipulation and still very new to a lot of javascript...as you can probably tell by my code!
I'm messing around with a tip calculator (pretty standard newbie project I guess) and having real difficulties with the DOM and how to select certain elements from inputs (text and radio) and have them submit.
Any advice on my below code would be awesome. I am all ears and ready to take a spanking for all of the mistakes...but super keen to learn what I'm doing wrong!
<form class="container">
<h2>Tip Calculator</h2>
<p>Enter Bill Amount</p>
<input type="text" class="input-styles" placeholder="£££" id="bill-amount">
<p>Select Percentage Of Bill</p>
<div class="radio-container">
<div class="radio-styles"> <p>10%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.1">
</div>
<div class="radio-styles">
<p>15%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.15">
</div>
<div class="radio-styles">
<p>20%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.2">
</div>
<div class="radio-styles">
<p>25%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.25">
</div>
</div>
<div class="submit-container">
<button type="submit" name="tip-submit" id="submit-button">submit</button>
</div>
<div class="totals-container">
<div class="totals">
<h2>Tip To Pay</h2>
<h2 id="tip-to-pay"></h2>
<h2 id="bill-final">Total Bill To Pay</h2>
<h2 id="bill-to-pay"></h2>
</div>
</div>
</form>
Javascript below...
var bill, percent, tip, finalBill;
document.getElementById('submit-button').addEventListener('click', function() {
// get bill amount
bill = document.getElementById('bill-amount').value
//get percent amount from checkboxes
percent = document.getElementsByName('tip-percent').checked;
tip = calcTip();
finalBill = finalAmount();
// edit results in html
document.getElementById('tip-to-pay').textContent = tip;
document.getElementById('bill-to-pay').textContent = finalBill;
// display result
document.querySelector('.totals-container').style.display = 'flex';
}
function calcTip() {
tip = percent * bill
}
function finalAmount() {
finalBill = tip + bill
}
probably be a lot easier to see this with my below pen!
https://codepen.io/rickwall/pen/WNbpmoW

HTML
On your HTML, you're wrapping your calculator with <form class="container"> - Forms are typically used for sending data to a web-server, for submission or validation among other things. In this case, you're just using it as a container and so are fine to stick to a standard <div>
This was causing the issue with your calculator disappearing when you submit
JavaScript
Scoping - Originally you were defining all of your variables in the global scope, rather than the function scope. This is typically avoided because it can cause issues with variables overwriting, losing track of changes, generally unexpected behaviour - You can ready more about this here
Functions - Your functions were perhaps a product of your scoping, but in general you would want your functions to take an input, and return you a value rather than modifying the values outside of the function scope - Returning your output helps avoid unexpected changes, while using parameters to input values allows more control and readability
In this code, I would be tempted to just not use the functions and perform the maths directly, being as it's simple & called only once - But you're free to do as you want
// This will change the value of tip globally, while also using set variables for percent and bill
function calcTip () {
tip = percent * bill
}
// This allows us to return the output of our function to our chosen variable
// while also taking the inputs we want
function calcTip (percent, bill) {
return percent * bill;
}
let tip = calcTip(0.10, 120); // returns 12;
Read more about functions from the MDN Docs
Types - In your main function, you're retrieving the .value of elements, and assigning them to bill and percent. However, .value will return a String, regardless of if the input is a "a" character, or a "2" character - This is causing issues when you're trying to add values, because the add operator + does different things when used with Strings and Numbers.
For example, when used with a String and a Number, it will simply concatinate the two variables together - not add them as you might expect
let a = "5"; // Type: String
let b = 120; // Type: Number
a + b // "5120"
The correct behavior is seen when used with two Numbers
let a = 5; // Type: Number
let b = 120; // Type: Number
a + b // 125
In your case, we can make our String values bill & percent into Numbers by using parseInt(x) and parseFloat(x) - parseInt converts to an integer Number, while parseFloat converts to a floating point Number
There are a few more minor changes to your code in the snippet, but this is just some quick things for you before you post this over to code review - by no means is this the absolute correct way to do this, there's a fair few, but it's hopefully gonna help you moving forward
document.getElementById('submit-button').addEventListener('click', function() {
// Get bill amount
let bill = parseInt(document.getElementById('bill-amount').value);
// Get percent from selected checkbox
/* let percent = document.getElementsByName('tip-percent'); */
let percent = parseFloat(document.querySelector('input[name="tip-percent"]:checked').value);
// No reason to have these as functions if they're simple & only called once
let tip = percent * bill;
let finalBill = bill + tip;
// Add results in html
document.getElementById('tip-to-pay').textContent = '$' + tip;
document.getElementById('bill-to-pay').textContent = '$' + finalBill;
// Dislay result
document.querySelector('.totals-container').style.display = 'flex';
})
* {
margin: 0;
padding: 0;
}
html {
font-family: zilla slab;
font-size: 18px;
font-weight: 300;
background-image: url(imgs/restaurant.jpg);
background-position: center;
}
.page {
display: flex;
justify-content: center;
align-items: center;
}
.container {
display: flex;
justify-content: center;
flex-direction: column;
background-color: rgba(204, 238, 255, 0.9);
padding: 50px 100px 50px 100px;
margin-top: 2%;
text-align: center;
box-shadow: 0px 8px 40px rgba(0, 0, 0, 0.5), 0px 10px 20px rgba(0, 0, 0, 0.7);
border-radius: 40px;
}
.container>h2 {
padding-bottom: 1.6rem;
font-size: 2.5rem;
}
.container>p {
padding-bottom: 1rem;
font-size: 1.5rem;
}
.container>input {
text-align: center;
padding: 4px;
font-size: 1.2rem;
width: 160px;
margin-left: 19%;
margin-bottom: 1rem;
}
.radio-container {
display: flex;
justify-content: space-between;
}
.radio-box {
display: flex;
text-align: center;
align-items: center;
flex-direction: column;
}
.radio-styles {
margin: 10px 0 1.2rem 0;
cursor: pointer;
outline: none;
}
button {
padding: 8px 40px 8px 40px;
text-transform: uppercase;
background-color: #fff;
border: none;
border-radius: 45px;
box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease 0s;
cursor: pointer;
outline: none;
font-family: zilla slab;
font-weight: 300;
font-size: 1rem;
}
.totals-container {
display: none;
}
.totals {
display: flex;
flex-direction: column;
}
#bill-final {
font-size: 2rem;
}
.totals h2 {
padding-bottom: 1.6rem;
}
<div class="page">
<div class="container">
<h2>Tip Calculator</h2>
<p>Enter Bill Amount</p>
<input type="text" class="input-styles" placeholder="£££" id="bill-amount">
<p>Select Percentage Of Bill</p>
<div class="radio-container">
<div class="radio-styles">
<p>10%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.10">
</div>
<div class="radio-styles">
<p>15%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.15">
</div>
<div class="radio-styles">
<p>20%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.20">
</div>
<div class="radio-styles">
<p>25%</p>
<input type="radio" class="radio-styles" name="tip-percent" value="0.25">
</div>
</div>
<div class="submit-container">
<button type="submit" name="tip-submit" id="submit-button">submit</button>
</div>
<div class="totals-container">
<div class="totals">
<h2>Tip To Pay</h2>
<h2 id="tip-to-pay"></h2>
<h2 id="bill-final">Total Bill To Pay</h2>
<h2 id="bill-to-pay"></h2>
</div>
</div>
</div>
</div>

Related

Format currency input field with dollar sign & commas

I have a revenue input field in a javascript/jquery form:
Need a dollar sign :before
add commas as the currency increases
I have a dollar sign showing via css, but issues centering it and ensuring the field entry point is next to it without overlapping. Unsure how to do the commas. Any suggestions or tips are welcome!
HTML:
<form id="rev-calculator">
<label for="price">Monthly Revenue</label>
<div class="fields">
<input type="number" name="price" id="price" min="0" max="10000000000" required data-type="number"> </input>
<br>
</form>
CSS:
<style>
.body {
text-align: left;
}
.fields {
margin: 0 10px 0 0;
}
.fields:before {
content: "$";
text-align: center;
position: relative;
left:30px;
}
#price {
border-radius: 5px;
margin: 15px;
padding: 10px;
color: black;
}
</style>
JS:
<script>
$('#rev-calculator').on('click', 'button', function(e) {
e.preventDefault();
var price = $("#price").val();
console.log(price);
})
</script>
codepen: https://codepen.io/kedarPE/pen/JjroYyb
input field
Well here's a way, though in truth not as simple as I hoped when I started down this path. You can use Intl.NumberFormat to get the comma in there (according to locale). To accomodate decimals, I sniff for them in the beginning and append them to the result.
To allow for the comma, I made this a text field with a pattern attribute. Also, I adjusted your CSS to make it a little nicer looking with the $
$('#price').keydown(function(e) {
setTimeout(() => {
let parts = $(this).val().split(".");
let v = parts[0].replace(/\D/g, ""),
dec = parts[1]
let calc_num = Number((dec !== undefined ? v + "." + dec : v));
// use this for numeric calculations
// console.log('number for calculations: ', calc_num);
let n = new Intl.NumberFormat('en-EN').format(v);
n = dec !== undefined ? n + "." + dec : n;
$(this).val(n);
})
})
.body {
text-align: left;
}
.fields {
margin: 0 10px 0 0;
}
.fields:before {
content: "$";
text-align: center;
position: relative;
left: 35px;
}
#price {
border-radius: 5px;
margin: 15px;
padding: 10px 10px 10px 20px;
color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="rev-calculator">
<label for="price">Monthly Revenue</label>
<div class="fields">
<input type="text" pattern="[0-9.,]+" name="price" id="price" required data-type="number" />
<br>
</form>
I'm surprised the unique answer for this issue has a lot of votes because it has a tiny but major flaw: the event shouldn't be keydown, it should be keyup. If you use keydown, it won't read the keys you are pressing at the moment but the previous one. So, please update your answer.

Hex to rgb converter in javascript

I'm trying to make a simple rgb to hex converter and I keep getting stuck with Javascript, what am I doing wrong?
In html part I made a form which on submit calls convert() function.
function convert() {
r = parseInt(document.getElementById('r').value);
g = parseInt(document.getElementById('g').value);
b = parseInt(document.getElementById('b').value);
rgb(r, g, b);
function rgb(r, g, b){
res = ColorToHex(r) + ColorToHex(g) + ColorToHex(b);
function ColorToHex(color) {
if (color > 255) return "FF";
else if (color < 0) return "00";
else color.toString(16).padStart(2, "0").toUpperCase();
}
}
document.getElementById('result').innerHTML = res;
return false;
}
This returns hex from RGB
console.log(convert('255','18', '50'));
function convert(r, g, b) {
r = parseInt(r); g = parseInt(g); b = parseInt(b);
res = r.toString(16) + g.toString(16) + b.toString(16);
res = res.toUpperCase();
return res;
}
First, please declare your variables properly. I don't know what else you have going on in the rest of your code, it may or may not be a factor.
Second, I don't know what you are doing in your HTML. From the code shown, I am assuming your HTML has something like:
<input id="r" type="number"/>
<input id="g" type="number"/>
<input id="b" type="number"/>
And
<span id="result">This Space For Lease</span>
Though I gather you have some of that enclosed in a <form> with a submit button, which is not strictly necessary. For instance you could use something like onBlur to call convert() every time you make any input change for a more dynamic UX. And further, use ' onclick="select()" ` so that when you click in an input it auto-selects the existing contents.
Other optimizations noted in the comments in the below example.
<body>
<h3>Enter integer RGB values</h3>
<input id="r" type="number" onclick="select()" onblur="convert()" value="00" style="width: 5em; background:#fcc;" />
<input id="g" type="number" onclick="select()" onblur="convert()" value="00" style="width: 5em; background:#cfc;" />
<input id="b" type="number" onclick="select()" onblur="convert()" value="00" style="width: 5em; background:#ccf;" />
<br>
<h3>Result as a HEX string</h3>
<div style="margin:1em 0.5em; padding: 0.5em 0;">THE COLOR IS:
<span id="colorPatch" style="margin: 0.5em; padding: 1em; background-color: black; border-radius: 0.6em;"> </span><br>
<span id="result">#000000</span>
</div>
</body>
<script>
// create variables for all "getElement..." this was the DOM
// only needs to be parsed on page load, so future access to
// the elements is via the variable instead for better performance.
let inputR = document.getElementById('r'),
inputG = document.getElementById('g'),
inputB = document.getElementById('b'),
resultOut = document.getElementById('result'),
colorOut = document.getElementById('colorPatch');
function convert() {
// here making the assumption that the expected inputs are
// unsigned integers, we clamp the values to 0-255, then
// make each into a 2 char hex str with padding.
let hexR = Math.min(Math.max(inputR.value, 0), 255).toString(16).padStart(2, "0"),
hexG = Math.min(Math.max(inputG.value, 0), 255).toString(16).padStart(2, "0"),
hexB = Math.min(Math.max(inputB.value, 0), 255).toString(16).padStart(2, "0");
// concatenate to a hex color string
let resultColor = "#" + hexR + hexG + hexB;
// Send to output and set color of sample color patch.
// toUpperCase() is performed once on the final string,
// instead of the substrings
resultOut.innerHTML =
colorOut.style.backgroundColor = resultColor.toUpperCase();
}
</script>
And also added it as a snippet below. Please do read the code comments as they explain what and why things are as they are.
Now, as for the concatenation, it could be even tighter:
function convert() {
colorOut.style.backgroundColor =
resultOut.innerHTML = ("#"
+ Math.min(Math.max(inputR.value,0),255).toString(16).padStart(2,"0")
+ Math.min(Math.max(inputG.value,0),255).toString(16).padStart(2,"0")
+ Math.min(Math.max(inputB.value,0),255).toString(16).padStart(2,"0")).toUpperCase();
}
Everything all on one logical line (line breaks added only for readability), so no need to declare and assign any more variables. Though this kind of thing can impact code readability if taken too far.
When making big strings, I like to put the concatenation operator (+) at the head of each line, which is the opposite of how I'd breakup a long equation by putting the math operators at the end of each line. This makes it clear the + is for concatenation and not addition.
Let me know if any questions...
// create variables for all "getElement..." this was the DOM
// only needs to be parsed on page load, so future access to
// the elements is via the variable instead for better
let inputR = document.getElementById('r'),
inputG = document.getElementById('g'),
inputB = document.getElementById('b'),
resultOut = document.getElementById('result'),
colorOut = document.getElementById('colorPatch');
function convert() {
// here making the assumption that the expected inputs are
// unsigned integers, we clamp the values to 0-255, then
// make each into a 2 char hex str with padding.
let hexR = Math.min(Math.max(inputR.value, 0), 255).toString(16).padStart(2, "0"),
hexG = Math.min(Math.max(inputG.value, 0), 255).toString(16).padStart(2, "0"),
hexB = Math.min(Math.max(inputB.value, 0), 255).toString(16).padStart(2, "0");
// concatenate to a hex color string
let resultColor = "#" + hexR + hexG + hexB;
// Send to output and set color of sample color patch.
// toUpperCase() is performed once on the final string,
// instead of the substrings
resultOut.innerHTML =
colorOut.style.backgroundColor = resultColor.toUpperCase();
}
body {
margin: 0;
padding: 0.5em 1.5em ;
font-family: sans-serif;
background-color: #ffd;
}
h2, h3 { position: relative; font-style: oblique; }
h2 { margin: 0.5em 1em 0.5em;}
h3 { margin: 0.5em 2em 1.4em;}
#r,#g,#b {
width: 5em;
height: 1.75em;
font-size: 1.33em;
font-weight: 600;
text-align: center;
border-radius: 0.6em;
}
#r { background:#fcc; }
#g { background:#cfc; }
#b { background:#ccf; }
.resultDiv {
display: inline-block;
position: relative;
margin: 1.33em;
padding: 0.5em 0.5em 2em;
background-color: #4bb4;
border-radius: 2em;
text-shadow: 0.15em 0.15em 0.3em #6886;
box-shadow: inset 3px 3px 6px #0448,
inset 0 0 22px #4888;
}
.resultVal {
position: relative;
margin: 1em 2em;
padding: 0em;
}
#result {
font-size: 1.5em;
font-weight: 500;
letter-spacing: 0.07em;
color: #135a;
text-shadow: -0.05em -0.05em 0.08em #defd,
0.05em 0.05em 0.08em #1238;
}
#colorPatch {
min-width: 5em;
margin: 0.5em;
padding: 0.5em 1em 2em;
font-size: 1.25em;
background-color: black;
border: 0.33em solid #999;
border-radius: 0.75em;
box-shadow: 2px 2px 3px #2449;
}
<body>
<h2>Enter integer RGB values</h2>
<input id="r" type="number" onclick="select()" onblur="convert()" value="00"/>
<input id="g" type="number" onclick="select()" onblur="convert()" value="00"/>
<input id="b" type="number" onclick="select()" onblur="convert()" value="00"/>
<br>
<div class="resultDiv">
<h3>Result as a HEX string</h3>
<div class="resultVal">THE COLOR IS:
<span id="colorPatch" > </span><br>
<span id="result">#000000</span>
</div>
</div>
</body>

Function releases after page is loaded not after click

I'm trying to make a game of little rabbit's farm. My level of programming is a beginner.
Why is addRabbit() code starts to work after the page is loaded? I wrote it to work after click to "Buy Rabbit" button
Why rabbits are not shown at the page near the "Sell Rabbit" and "Buy Rabbit" buttons?
I know that I have a lot of issues here as far as I'm a beginner. Could I ask you to mention any of them?
// VARIABLES
// variables for modal of chosing rabbits
const chooseModal = document.querySelector(".choose-modal");
const selectRabbitBtn = document.querySelector(".choose-rabbit-btn");
const rabbitSelects = document.querySelectorAll("input[type=radio]");
let chosenRabbitUrl = "img/rabbit1.png";
// start screen
const startScreenDiv = document.querySelector(".story-modal");
const rabbit = document.querySelector("img.rabbit");
const buyRabbitBtn = document.querySelector(".buy-btn");
// EVENT LISTENERS
selectRabbitBtn.addEventListener("click", chooseTheRabbit);
// FUNCTIONS
function chooseTheRabbit(e){
e.preventDefault();
for (let rabbit of rabbitSelects) {
if (rabbit.checked) {
chosenRabbitUrl = `img/${rabbit.id}.png`;
break;
}
}
chooseModal.style.display = "none";
startScreen();
}
function startScreen() {
startScreenDiv.style.display = "block";
rabbit.src = chosenRabbitUrl;
}
class RabbitGame {
constructor() {
this.rabbitsCount = parseInt(document.querySelector(".rabbits-count").innerText, 10);
this.rabbitsCountSpan = document.querySelector(".rabbits-count");
this.rabbitsShowDiv = document.querySelector(".rabbits-count-show");
this.coinsCount = parseInt(document.querySelector(".coins-count").innerText, 10);
this.coinsCountSpan = document.querySelector(".coins-count");
this.sellRabbitBtn = document.querySelector(".sell-btn");
this.myRabbits = [{age: 0, src: chosenRabbitUrl, width: 50}];
};
// function, that shows rabbits on the page, that the owner have
// adult rabbits should be bigger, little rabbits smaller
showRabbits() {
// rabbit.src = chosenRabbitUrl
this.myRabbits.forEach((rabbit) => {
this.rabbitsShowDiv.innerHTML += `<img src="${rabbit.src}" width="${rabbit.width}">`});
};
// function that adds a rabbit, if the owner doesn't have any coin, rabbits eat him
addRabbit() {
console.log("Hello");
if (this.coinsCount > 1) {
// remove 1 coin
this.coinsCount -= 1
console.log(this.coinsCount);
// show 1 coin less
this.coinsCountSpan.innerText = this.coinsCount
// add 1 for rabbits age
// if the rabbit is older than 4, make him bigger on screen
this.myRabbits.forEach((rabbit) => {
rabbit.age +=1;
if (rabbit.age > 3) {
rabbit.width = 70
}
})
// add 1 more rabbit to array
this.myRabbits.push({age: 0, src: chosenRabbitUrl, width: 50});
// show 1 more rabbit
this.rabbitsShowDiv.innerHTML += `<img src="${rabbit.src}" width="${rabbit.width}">`
}
};
// функция, которая продает кролика, если он взрослый
// если нет взрослых кроликов, выводит предупреждение, что нет взрослых кроликов
}
const rabbitGame = new RabbitGame();
rabbitGame.showRabbits;
buyRabbitBtn.addEventListener("click", rabbitGame.addRabbit());
/* GENERAL */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
h3 {
background-color: rgb(108, 165, 55);
width: 400px;
height: 30px;
padding: 5px;
color: white;
text-align: center;
}
button {
padding: 5px 20px;
background-color: rgb(194, 89, 89);
color: white;
text-transform: uppercase;
border: none;
font-weight: bold;
}
button:hover {
background-color: rgb(172, 79, 84);
}
/* END OF GENERAL */
/* CHOOSE RABBIT MODAL & RULES MODAL */
.choose-modal,
.rules-modal {
display: flex;
justify-content: center;
margin-top: 20px;
}
.choose-modal > div {
display: flex;
flex-direction: column;
}
input[type="radio"] {
opacity: 0;
}
label > img:hover {
border-bottom: 1px solid rgb(199, 199, 199);
}
ul {
list-style: none;
margin: 10px;
}
li {
margin-bottom: 5px;
}
.button-div {
display: flex;
justify-content: center;
}
/* END OF CHOOSE RABBIT MODAL & RULES MODAL */
/* START SCREEN */
/* .story-modal {
display: none;
} */
.story-modal {
background-image: url("img/neighbour.jpg");
background-size: cover;
height: 100vh;
position: relative;
}
img.rabbit {
position: absolute;
height: 40%;
top: 60%;
left: 50%;
overflow: hidden;
}
.story-modal > h3 {
position: absolute;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
top: 5%;
}
.img-overlay {
width: 100%;
height: 100%;
background: rgba(61, 61, 61, 0.3);
}
.story-modal > button {
position: absolute;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
top: 13%;
}
/* END OF START SCREEN */
/* MAIN GAME */
.main-game {
display: flex;
}
/* END OF MAIN GAME */
<div class="choose-modal">
<div>
<div class="choose-modal-header">
<h3>Please, choose the rabbit</h3>
</div>
<div>
<label for="rabbit1"><input type="radio" id="rabbit1" name="rabbits" value="rabbit1"><img src="img/rabbit1.png" width="100" alt="rabbit1"></label>
<label for="rabbit2"><input type="radio" id="rabbit2" name="rabbits" value="rabbit2"><img src="img/rabbit2.png" width="100" alt="rabbit2"></label>
<label for="rabbit3"><input type="radio" id="rabbit3" name="rabbits" value="rabbit3"><img src="img/rabbit3.png" width="80" alt="rabbit3"></label>
</div>
<div class="button-div">
<button type="submit" value="Choose" class="choose-rabbit-btn">Choose</button>
</div>
</div>
</div>
<div class="story-modal">
<div class="img-overlay"></div>
<h3>Your pretty neighbour gave you a rabbit</h3>
<img alt="rabbit" src="#" class="rabbit">
<button>Rules</button>
</div>
<div class="rules-modal">
<div>
<h3>Rules of game</h3>
<div>
<ul>
<li>Buy grass to feed the rabbits</li>
<li>Sell adult rabbits</li>
<li>Buy new little rabbits</li>
</ul>
</div>
<div class="button-div">
<button>Play</button>
</div>
</div>
</div>
<div class="main-game">
<div class=" navbar">
<p><img src="img/coin.png" height="20"> Coins <span class="coins-count">10</span></p>
<p class="name-of-gamer">Anonymous</p>
<p><img src="img/rabbit.png" height="20"> Rabbits <span class="rabbits-count">3</span></p>
</div>
<div class="rabbits-count-show"></div>
<div>
<button class="sell-btn">Sell Rabbit</button>
<button class="buy-btn">Buy Rabbit</button>
</div>
</div>
Changing the line
buyRabbitBtn.addEventListener("click", rabbitGame.addRabbit());
to
buyRabbitBtn.addEventListener("click", rabbitGame.addRabbit);
(simply removing those parenthesis) should work. When you add the parenthesis, a function gets called, and that's not what you want. When the button is clicked the eventlistener call the your function itself. as of your second problem you have to add parenthesis to the function to get called thus executing the code inside it.
NOTE: Do not post unnecessary files to a question. Try find the location that error could possibly occur. BTW, CSS has no contributing factor to a error in js code. sometimes html does. I know as a beginner it's hard to find the areas causing the error but it gets easier over time.

HTML JavaScript would not allow nor consider decimals

I am trying to create a calculator, to evaluate two payment options for an international online purchasing, to give best decision either to proceed with website original currency [which is different than buyer credit card currency] and in this case buyer bank exchange rate will apply, or to proceed with website preset exchange rate to match buyer credit card currency ignoring bank exchange rate.
The idea is that 1 USD equal to 3.75, and it varies sometimes, but few websites are setting their own exchange rate, and in our case sometimes if a customer buys using website exchange rate, it reaches to 1 USD equal to 4.
I am trying to give customers a better idea of which option to proceed with, as well as am adding many fields to consider, to show the best result possible, such as bank processing fees.
I have one issue, I could not make bank processing fees to be a percentage input and considered in the calculation. Thus, I thought the customer can enter the percentage as a value, and I will do the conversion in the code. For example, bank processing fees are 2.75%, I'll let the customer enter a value 2.75 and inside the code, I will have it work by conversion 2.75 / 100. After testing, I can see that code is calculation only an integer number of percentages, either 2 or 3, and so on; it does not consider decimals like in my case 2.75!
Pls, help if possible, to view solutions of the code amendment.
Thank you, and appreciate your insights!
// Do all your JavaScript in a separate JavaScript section
var main = document.getElementById("Dep-main");
var joint1 = document.getElementById("Dep-joint1");
var joint2 = document.getElementById("Dep-joint2");
var joint3 = document.getElementById("Dep-joint3");
var total = document.getElementById("Total-dep");
var inputs = Array.prototype.slice.call(document.querySelectorAll("div > input"));
inputs.forEach(function(input){
input.addEventListener("blur", function(){
// Always supply the second argument to parseInt() (the radix) so you
// dont' get non-base 10 answers.
total.value = (parseInt(main.value, 10) * parseInt(joint1.value, 10)) + (parseInt(joint3.value, 10)) + (parseInt(main.value, 10) * ((parseInt(joint2.value, 10) / 100)));
});
});
label {
display: block;
text-align: center;
line-height: 150%;
font-size: .85em;
}
input[type=text], select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
text-align: center;
}
input[type=submit] {
width: 100%;
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
div {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
.center {
margin: auto;
width: 60%;
border: 3px solid #73AD21;
padding: 10px;
}
<!DOCTYPE html>
<html>
<body>
<br>
<center><img src="https://logos-download.com/wp-content/uploads/2016/03/Asos_logo.png" width="270" height="108"></center>
<br>
<center><h3>Best Payment Option Evaluator</h3></center>
<br>
<div class="center">
<label for="dep-nothing">Enter ASOS total amount in SAR [using ASOS Site Exchange Rate]</label>
<input type="text" id="dep-nothing" value="0">
<hr>
<label for="dep-main">Ebter total amount in USD</label>
<input type="text" id="Dep-main" value="0">
<label for="dep-joint1">Enter todays exchange rate from your bank [1 USD = X SAR]</label>
<input type="text" id="Dep-joint1" value="0">
<label for="dep-joint2">Enter bank fees in numbers [will be converted into percentage]</label>
<input type="text" id="Dep-joint2" value="0">
<label for="dep-joint3">Enter buyer commission value in SAR</label>
<input type="text" id="Dep-joint3" value="0">
<label for="total-dep"><b>If you proceed with USD, below amount will be deducted from your bank accoutn in SAR , <mark>Approx.</mark></b></label>
<input type="text" id="Total-dep" disabled readonly>
</div>
<br>
</body>
</html>
You are using parseInt() (which converts the result to whole numbers), try using parseFloat() instead.
replace parseInt by parseFloat, you can use .toFixed with parse float to limit deci
For decimal number you have to use .parseFloat() function, not .pareseInt()
// Do all your JavaScript in a separate JavaScript section
var main = document.getElementById("Dep-main");
var joint1 = document.getElementById("Dep-joint1");
var joint2 = document.getElementById("Dep-joint2");
var joint3 = document.getElementById("Dep-joint3");
var total = document.getElementById("Total-dep");
var inputs = Array.prototype.slice.call(document.querySelectorAll("div > input"));
inputs.forEach(function(input){
input.addEventListener("blur", function(){
// Always supply the second argument to parseInt() (the radix) so you
// dont' get non-base 10 answers.
total.value = (parseFloat(main.value) * parseFloat(joint1.value)) + (parseFloat(joint3.value)) + (parseFloat(main.value) * ((parseFloat(joint2.value) / 100)));
});
});
label {
display: block;
text-align: center;
line-height: 150%;
font-size: .85em;
}
input[type=text], select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
text-align: center;
}
input[type=submit] {
width: 100%;
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
div {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
.center {
margin: auto;
width: 60%;
border: 3px solid #73AD21;
padding: 10px;
}
<!DOCTYPE html>
<html>
<body>
<br>
<center><img src="https://logos-download.com/wp-content/uploads/2016/03/Asos_logo.png" width="270" height="108"></center>
<br>
<center><h3>Best Payment Option Evaluator</h3></center>
<br>
<div class="center">
<label for="dep-nothing">Enter ASOS total amount in SAR [using ASOS Site Exchange Rate]</label>
<input type="text" id="dep-nothing" value="0">
<hr>
<label for="dep-main">Ebter total amount in USD</label>
<input type="text" id="Dep-main" value="0">
<label for="dep-joint1">Enter todays exchange rate from your bank [1 USD = X SAR]</label>
<input type="text" id="Dep-joint1" value="0">
<label for="dep-joint2">Enter bank fees in numbers [will be converted into percentage]</label>
<input type="text" id="Dep-joint2" value="0">
<label for="dep-joint3">Enter buyer commission value in SAR</label>
<input type="text" id="Dep-joint3" value="0">
<label for="total-dep"><b>If you proceed with USD, below amount will be deducted from your bank accoutn in SAR , <mark>Approx.</mark></b></label>
<input type="text" id="Total-dep" disabled readonly>
</div>
<br>
</body>
</html>
The parseInt() function is the course of the problem. Whenever this function is used, it converts the value passed to it to an integer by truncation the decimal value. For example parseInt("2.7")= 2.
You can use the following instead.
total.value = (parseInt(main.value, 10) * parseInt(joint1.value, 10)) + (parseInt(joint3.value, 10)) + (parseInt(main.value, 10) * ((parseFloat(joint2.value, 10) / 100)));

Javascript Slider with Multiple Allowed sections/timeslots

I want to implement a time-slot selector in jquery/javascript slider form.
There are a few slider libraries out there such as Ion Slider, jQRangeSlider etc. but I don't know how I would be going about this. It doesn't look like they support multiple "dead-zones".
I want the user to be able to select a timeslot (from and to) during a particular day. To select the day, I have implemented a date picker, then for the date, I retrieve the already occupied slots for instance:
07h00 - Available
07h30 - Available
08h00 - Occupied
08h30 - Occupied
09h00 - Occupied
09h30 - Available
...
18h30 - Available
19h00 - Available
So the range picker must look like this:
The user should only be able to select a time zone in the available sections (blue) and drag the start slider between the "available" section, and the end selector will move along with it. There might be multiple unavailable zones (Red).
Is this possible with the libraries already out there or is this a case of roll my own?
I have thought about using a bunch of check boxes then check all the boxes between the start and end time-slots, and disable the already occupied slots, but I think a slider like this would be much more user friendly to use, functionally and visually.
A double slider can be made with very little effort by overlaying two sliders on top of each other using CSS. You need to listen to the onchange events of these two and reset the slider to previous value or closet non dead region when set to a dead region.
var deadZones = [[2,3], [6,7]];
function showVal(input) {
deadZones.forEach(([from, to]) => {
// reset to old value if in dead zone
if(from <= input.value && input.value <= to)
input.value = input.oldValue;
});
input.oldValue = input.value;
//console.log(input.id, input.value);
displayValues();
}
function displayValues() {
var a = $('#a').val();
var b = $('#b').val();
$('#slider-values').text(`Min: ${Math.min(a,b)} Max: ${Math.max(a,b)}`);
}
displayValues();
html,body{
margin: 0; padding: 0;
}
#a, #b{
position: absolute;
top: 30px;
display: block;
z-index: 100;
}
#b {
top: 60px;
}
/* from: https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ */
input[type=range] {
-webkit-appearance: none; /* Hides the slider so that custom slider can be made */
width: 90%; /* Specific width is required for Firefox. */
background: transparent; /* Otherwise white in Chrome */
margin-left: 5%;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
automatic */
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; /* Add cool effects to your sliders! */
position: relative;
}
input[type=range]#a::-webkit-slider-thumb {
top: 100px;
}
input[type=range]#b::-webkit-slider-thumb {
top: 70px;
}
.slider-bg {
width: 100%;
margin: 0; padding: 0;
margin-left: 2.5%;
position: relative;
z-index: 1;
top: 135px;
}
.slider-bg div {
display: inline-block;
width: 9%;
margin: 0; padding: 0;
text-align: center;
border-top: 1px solid green;
padding-top: 20px;
}
.slider-bg div.disabled {
border-top: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="a" type="range" min="1" max="10" value="1" oninput="showVal(this)" onchange="showVal(this)" />
<input id="b" type="range" min="1" max="10" value="9" oninput="showVal(this)" onchange="showVal(this)"/>
<hr />
<div class="slider-bg">
<div>1</div>
<div class="disabled">2</div>
<div class="disabled">3</div>
<div>4</div>
<div>5</div>
<div class="disabled">6</div>
<div class="disabled">7</div>
<div>8</div>
<div>9</div>
<div>10</div>
</div>
<div id="slider-values"></div>
I have decided to implement an ionRangeSlider with custom slots from 05h30 to 19h30. A separate array of used time-slots to which I compare in the onChange event.
var slider = $("#timeslotSlider").ionRangeSlider({
type: "double",
grid: true,
from: 1,
from_value: "06h00",
to: 2,
to_value: "06h30",
values: timeslotvalues,
onChange: function (data) {
timeslotSetSelectedText(data);
}
});
var sliderdata = slider.data("ionRangeSlider");
var dt = sliderdata.result.from_value != null ? sliderdata.result : sliderdata.options;
timeslotSetSelectedText(dt);
The timeslotSetSelectedText function compares the selected range to the used slots then display a message "Available" or "Overlaps Existing time-slot"
The same function is used to Validate the selected slot before sending it to the server.

Categories

Resources