in my class we are using firstChild.nodeValue to display text if a user enters in an incorrect value. However, I can't get my two other fields to display the error message and only the first one. What am I doing wrong? When I run it in the code snipped is says that the nodeValue is null. I have the error messages display through a span and they are being used by the firstChild.nodeValue.
var $ = function (id) {
return document.getElementById(id);
}
var calculateClick = function () {
var investment = parseInt( $("investment").value);
var rate = parseFloat( $("rate").value);
var years = parseInt($("years").value);
//var amount = interest * rate * years;
if (investment==="" || investment < 100 || investment > 100000){
$("investment_error").firstChild.nodeValue="Must be an integer from 100 - 100,000";
}
else if (rate ==="" || rate <0.1 || rate >12){
$("rate_error").firstChild.nodeValue="Must be a value from .1 - 12";
}
else if (years ==="" || years <1 || years > 50){
$("years_error").firstChild.nodeValue="Must be an integer from 1 - 50";
}
var nt = 4*years;
var amount = investment * (1 + (rate/4)) ** nt;
$("future_value").value=amount.toFixed(2);
}
var clear_fields = function (){
$("investment").value="";
$("rate").value="";
$("years").value="";
$("future_value").value="";
}
window.onload = function () {
$("calculate").onclick = calculateClick;
$("calculate").ondblclick=clear_fields;
$("investment").focus();
}
body {
font-family: Arial, Helvetica, sans-serif;
background-color: white;
margin: 0 auto;
width: 48%;
padding: 0 1em .5em;
border: 3px solid blue;
}
h1 {
margin: .5em 0;
text-align: center;
}
label {
float: left;
width: 10em;
text-align: right;
padding-bottom: .5em;
}
input {
margin-left: 1em;
margin-bottom: .5em;
}
span {
color: blue;
}
<!DOCTYPE html>
<html>
<head>
<title>Future Value Calculator</title>
<link rel="stylesheet" href="future_value.css">
<script src="future_value.js"></script>
</head>
<body>
<main>
<h1 id="heading">Future Value Calculator</h1>
<label for="investment">Investment Amount:</label>
<input type="text" id="investment">
<span id="investment_error"> </span><br>
<label for="rate">Annual Interest Rate:</label>
<input type="text" id="rate">
<span id="rate_error"></span><br>
<label for="years">Number of Years:</label>
<input type="text" id="years">
<span id="years_error"></span><br>
<label for="future_value">Future Value:</label>
<input type="text" id="future_value" disabled="disabled"><br>
<label> </label>
<input type="button" id="calculate" value="Calculate"><br>
</main>
</body>
</html>
Its working on the first span becouse you have space between the span tags as:
with space
<span id="investment_error"> </span>
without
<span id="rate_error"></span>
In any case you should use innerHTML instead.
first child is good in case you already have a child in the html tags like this
<div>
<p id="i_am_div_first_child"> first child</p>
</div>
please hit correct answer if that was helpfull.
So what is the difference? A simple test will show you why.
console.log("1:", document.querySelector("#s1").firstChild)
console.log("2:", document.querySelector("#s2").firstChild)
<span id="s1"> </span>
<span id="s2"></span>
The one has a whitespace in it, the others do not the one with the whitespace has a firstChild, the others do not.
What should you do?
I would just set the textContent or innerHTML of the span and not set the nodeValue.
And another issue with your code, is you have
var rate = parseFloat( $("rate").value);
and
if ( rate==="")
That empty string check is not going to happen to be true ever since parseFloat is going to return NaN.
$("rate_error").firstChild returns null because it has no childrne (not even whit space), and so does not have a nodeValue property.
You could just use innerHTML instead of firstChild.nodeValue.
Also you don't need the else, just tell the user immediately all they have to fix.
var $ = function(id) {
return document.getElementById(id);
}
var calculateClick = function() {
var investment = parseInt($("investment").value);
var rate = parseFloat($("rate").value);
var years = parseInt($("years").value);
//var amount = interest * rate * years;
if (investment === "" || investment < 100 || investment > 100000) {
$("investment_error").innerHTML = "Must be an integer from 100 - 100,000";
}
if (rate === "" || rate < 0.1 || rate > 12) {
$("rate_error").innerHTML = "Must be a value from .1 - 12";
}
if (years === "" || years < 1 || years > 50) {
$("years_error").innerHTML = "Must be an integer from 1 - 50";
}
var nt = 4 * years;
var amount = investment * (1 + (rate / 4)) ** nt;
$("future_value").value = amount.toFixed(2);
}
var clear_fields = function() {
$("investment").value = "";
$("rate").value = "";
$("years").value = "";
$("future_value").value = "";
}
window.onload = function() {
$("calculate").onclick = calculateClick;
$("calculate").ondblclick = clear_fields;
$("investment").focus();
}
body {
font-family: Arial, Helvetica, sans-serif;
background-color: white;
margin: 0 auto;
width: 48 %;
padding: 0 1em .5em;
border: 3px solid blue;
}
h1 {
margin: .5em 0;
text-align: center;
}
label {
float: left;
width: 10em;
text-align: right;
padding-bottom: .5em;
}
input {
margin-left: 1em;
margin-bottom: .5em;
}
span {
color: blue;
}
<!DOCTYPE html>
<html>
<head>
<title>Future Value Calculator</title>
<link rel="stylesheet" href="future_value.css">
<script src="future_value.js"></script>
</head>
<body>
<main>
<h1 id="heading">Future Value Calculator</h1>
<label for="investment">Investment Amount:</label>
<input type="text" id="investment">
<span id="investment_error"> </span><br>
<label for="rate">Annual Interest Rate:</label>
<input type="text" id="rate">
<span id="rate_error"></span><br>
<label for="years">Number of Years:</label>
<input type="text" id="years">
<span id="years_error"></span><br>
<label for="future_value">Future Value:</label>
<input type="text" id="future_value" disabled="disabled"><br>
<label> </label>
<input type="button" id="calculate" value="Calculate"><br>
</main>
</body>
</html>
Related
I have created this simple straight bet calculator using JavaScript.
It allows me to calculate, if it is a winning ticket, how much the payout will be.
How it works?
First I will enter the moneyLine number, which can be mostly any 3 digits number and I then enter the bet amount.
Now, the moneyLine can either be negative (-) if betting a favorite or positive (+) if betting the underdog.
Please see the code below:
For testing proposes, I use any -110 or 110 and then, any bet amount. But it can actually be any chosen moneyLine and betAmount.
// Single Straight Sports Bet Calculator
function betCalculator(moneyLine) {
var odds;
var betAmount = +prompt("Enter Bet Amount");
if (moneyLine >= 0) {
odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1;
} else {
odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1;
} return ((odds * betAmount).toFixed(2));
}
alert(betCalculator(+prompt("Enter Money Line")));
// Single Straight Sports Bet Calculator
function betCalculator(moneyLine) {
var odds;
var betAmount = +prompt("Enter Bet Amount");
if (moneyLine >= 0) {
odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1;
} else {
odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1;
} return ((odds * betAmount).toFixed(2));
}
alert(betCalculator(+prompt("Enter Money Line")));
And here is what I would like to have accomplished.
My desire is to create a Parlay Calculator, using the above formulas, that will allow me to enter one bet amount and several money lines, instead of just one.
A parlay is a single bet that links together two or more individual wagers for a high payout. So a parlay ticket can have two or more teams on it.
What I would also like to do is to be able to enter those numbers (moneyLine and betAmount) on a form instead of a popup window.
I tried doing it myself with no avail. Somehow, it is not showing the result.
// True Odds Parlay Bets
const myForm= document.getElementById("my-form")
var odds;
var moneyLine
, trueOdds=
{ 'moneyLine1 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine2 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine3 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine4 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine5 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine6 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine7 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine8 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
, 'moneyLine9 >= 0': (odds = moneyLine >= 0 ? (moneyLine / 100) + 1 : (100 / Math.abs(moneyLine)) + 1)
};
myForm.onsubmit = e=>e.preventDefault(); // disable form submit
myForm.oninput = betCalculator;
function betCalculator() {
let bet = myForm.betAmount.valueAsNumber, odds = trueOdds[(myForm.moneyLine1.value + '_' + myForm.moneyLine2.value + '_' + myForm.moneyLine3.value + '_' + myForm.moneyLine4.value + '_' + myForm.moneyLine5.value + '_' + myForm.moneyLine6.value + '_' + myForm.moneyLine7.value + '_' + myForm.moneyLine8.value + '_' + myForm.moneyLine9.value)];
// This code is used to get rid of "NaN"
if ( isNaN(bet) || isNaN(odds) ) {
return 0;
}
myForm.result.value = '" ' + '$ '+(odds * bet).toFixed(2) + ' "'
}
betCalculator()
fieldset { margin-top: 1em;}
label { display: inline-block; width: 6em; }
input[type="radio"] {
-webkit-appearance: checkbox; /* Chrome, Safari, Opera */
-moz-appearance: checkbox; /* Firefox */
-ms-appearance: checkbox;
}
<head>
<title>True Odds Parlay Bet Calculator</title>
<link rel="stylesheet" type="text/css" href="trueoddstyle.css">
</head>
<body>
<h2>True Odds Parlay Bet Calculator</h2>
<p>
Useful for both <b>Negative "-"</b> and/or <b>Positive "+"</b> Money Lines including Single Straight Bets!
</p>
<form action="" id="my-form">
<fieldset>
<legend>Bet Amount :</legend>
<input type="number" name="betAmount" step=any min=0>
</fieldset>
<fieldset>
<legend>Team Respective Money Line :</legend>
<input type="number" name="moneyLine1" step=any min=0>
<input type="number" name="moneyLine2" step=any min=0>
<input type="number" name="moneyLine3" step=any min=0>
<input type="number" name="moneyLine4" step=any min=0>
<input type="number" name="moneyLine5" step=any min=0>
<input type="number" name="moneyLine6" step=any min=0>
<input type="number" name="moneyLine7" step=any min=0>
<input type="number" name="moneyLine8" step=any min=0>
<input type="number" name="moneyLine9" step=any min=0>
</fieldset>
<fieldset>
<legend>Payout :</legend>
<output name="result" value=''></output>
<br><br>
<input type="reset" value="Reset Calculator!"</input>
</fieldset>
</form>
</body>
Please see the snippet code for details.
Your help is very appreciated.
Revised first version :)
const bt_Nwline = document.getElementById('New-Line')
, xForm = document.getElementById('form-X')
, wTable = xForm.querySelector('table')
, baseLine = wTable.querySelector('thead tr:nth-of-type(3)')
, tBody = wTable.querySelector('tbody')
, tPayout = wTable.querySelector('tfoot td:nth-of-type(2)')
;
xForm.onsubmit = e=>e.preventDefault() // disable form submit
;
xForm.onreset =_=>{ tPayout.textContent = '0.00' }
;
function betCalculator()
{
let bet = xForm.betAmount.valueAsNumber || 0
, odds = [...tBody.querySelectorAll('input')]
.filter(ml=>!isNaN(ml.valueAsNumber) )
.reduce((odd,ml)=> odd *= ml.valueAsNumber >= 0
? (ml.valueAsNumber /100) +1
: (100 / Math.abs(ml.valueAsNumber)) +1
,1)
tPayout.textContent = ((odds *bet).toFixed(2)).replace(/\B(?=(\d{3})+(?!\d))/g,',')
}
betCalculator()
;
bt_Nwline.onclick=_=>
{
tBody.appendChild( baseLine.cloneNode(true))
}
tBody.onclick=e=>
{
if (!e.target.matches('button')) return
wTable.deleteRow(e.target.closest('tr').rowIndex)
betCalculator()
}
xForm.oninput = betCalculator
;
table { border-collapse: collapse; }
caption { background-color: #1a4641; color: whitesmoke; font-weight: bold; padding: .6em;}
td:nth-of-type(1) { min-width:8em; }
td { border: 1px solid grey; padding: .4em .8em; }
thead { background-color: #7adfd3; color: #1d1313; font-weight: bold; }
thead tr:nth-of-type(1) td:nth-of-type(1) { text-align: right; }
thead tr:nth-of-type(2) td:nth-of-type(1) { text-align: center; }
thead tr:nth-of-type(3) { display: none; counter-reset: line; }
tbody tr { counter-increment: line; }
tbody td:nth-of-type(1) { color: darkslategrey; }
tbody td:nth-of-type(1)::before { content: counter(line) '\00a0-\00a0\00a0'; }
tfoot { font-weight: bold; }
tfoot td:nth-of-type(1) { text-align: right; }
tfoot td:nth-of-type(2)::before { content: '$ ' }
input { font-size: 1.2em; text-align: right; direction: rtl; width:8em;}
button {
width: 2em;
height: 1.4em;
border-radius: 1em / .6em;
color: whitesmoke;
font-size: .9em;
font-weight: bolder;
line-height: .8em;
padding: 0;
}
thead tr:nth-of-type(1) button { background-color: #063329; }
thead tr:nth-of-type(2) button { background-color: crimson; }
tbody button { background-color: #071b3f;}
<form action="" id="form-X">
<table>
<caption title="Useful for both Negative ‘−’ and / or Positive ‘+’ Money Lines including Single Straight Bets!">
True Odds Parlay Bet Calculator
</caption>
<thead>
<tr>
<td>Bet Amount : </td>
<td><input type="number" step="10" value="0" name="betAmount" min="0"></td>
<td><button type="reset">∅</button></td>
</tr>
<tr><td colspan="2">Teams Money Lines</td> <td><button id="New-Line">+</button></td></tr>
<tr>
<td contenteditable spellcheck="false">...</td>
<td><input type="number" step="10" value="0"></td>
<td><button>−</button></td>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td> Payout : </td>
<td colspan="2"> </td>
</tr>
</tfoot>
</table>
</form>
After looking your second Snippet I do that:
const myForm = document.getElementById('my-form')
, moneyLines = [...myForm.querySelectorAll('.moneyLine')]
;
myForm.onsubmit = e=>e.preventDefault() // disable form submit
;
myForm.oninput = betCalculator
;
function betCalculator()
{
let bet = myForm.betAmount.valueAsNumber || 0
, odds = moneyLines
.filter(ml=>!isNaN(ml.valueAsNumber) )
.reduce((odd,ml)=> odd *= ml.valueAsNumber >= 0
? (ml.valueAsNumber /100) +1
: (100 / Math.abs(ml.valueAsNumber)) +1
,1)
myForm.result.value = (odds *bet).toFixed(2)
}
betCalculator()
form#my-form { position: relative; }
legend {font-size: .9em; }
legend:after { content: '\00a0' }
fieldset { display:block; width: 16em; position: absolute; }
fieldset:nth-child(1){ top: 1em; left: 1em; }
fieldset:nth-child(2){ top: 1em; left:20em; }
fieldset:nth-child(3){ top:19em; left: 1em; }
label { display: block; float: left; clear: both; margin: .2em 1em .4em 0;}
label b { display: inline-block; width:2em }
label b::after { content:' : '}
label input { font-size: 1.2em; text-align: right; direction: rtl; width:8em;}
output { font-weight: bold; width: 14em; border-bottom: 1px solid lightgrey; display: block; margin: .8em; float: right; text-align: right;}
output::before { content: '$ '; }
<h2>True Odds Parlay Bet Calculator</h2>
<p><small>
Useful for both <b>Negative "−"</b> and/or <b>Positive "+"</b> Money Lines including Single Straight Bets!
</small></p>
<form action="" id="my-form">
<fieldset>
<legend>Bet Amount :</legend>
<label><input type="number" name="betAmount" step=any min=0></label>
</fieldset>
<fieldset>
<legend>Team Respective Money Lines :</legend>
<label><b>1</b><input type="number" class="moneyLine" step=any ></label>
<label><b>2</b><input type="number" class="moneyLine" step=any ></label>
<label><b>3</b><input type="number" class="moneyLine" step=any ></label>
<label><b>4</b><input type="number" class="moneyLine" step=any ></label>
<label><b>5</b><input type="number" class="moneyLine" step=any ></label>
<label><b>6</b><input type="number" class="moneyLine" step=any ></label>
<label><b>7</b><input type="number" class="moneyLine" step=any ></label>
<label><b>8</b><input type="number" class="moneyLine" step=any ></label>
<label><b>9</b><input type="number" class="moneyLine" step=any ></label>
</fieldset>
<fieldset>
<legend>Payout :</legend>
<output name="result" value='0'></output>
<br><br>
<button type="reset">Reset Calculator!</button>
</fieldset>
</form>
What I don't understand is why does my code not change the text of the label when the radio is selected?
This is what is suppose to happen:
Which when 'Fahrenheit to Celsius' is selected the first image should be true (the text of the first and second label should change)
When 'Celsius to Fahrenheit' is selected the second image should be true (the text of the first and second label should change)
What I'm guessing is my problem is with the if ($("input:to_celsius").val() == "true") statement but I don't quite know why it's wrong.
***Current error message:
{
"message": "Uncaught TypeError: Cannot set property 'onclick' of null",
"filename": "https://stacksnippets.net/js",
"lineno": 69,
"colno": 30
}
"use strict";
var $ = function(id) { return document.getElementById(id); };
var clearTextBoxes = function() {
$("#degrees_entered").value = "";
$("#degrees_computed").value = "";
};
window.onload = function() {
$("#to_celsius").onclick = toCelsius;
$("#to_fahrenheit").onclick = toFahrenheit;
$("#degrees_entered").focus();
};
// Change the text of label 1 and 2 when the radio 'Celsius to Fahrenheit' is selected and clears all other inputs
var toFahrenheit = function() {
if ($("#to_fahrenheit").val() == "true") {
$("#degree_labl_1").text("Enter C degrees");
$("#degree_label_2").text("Degrees Fahrenheit");
clearTextBoxes();
}
}
// Change the text of label 1 and 2 when the radio 'Fahrenheit to Celsius' is selected and clears all other inputs
var toCelsius = function() {
if ($("#to_celsius").val() == "true") {
$("#degree_labl_1").text("Enter F degrees");
$("#degree_label_2").text("Degrees Celsius");
clearTextBoxes();
}
}
body {
font-family: Arial, Helvetica, sans-serif;
background-color: white;
margin: 0 auto;
width: 450px;
border: 3px solid blue;
}
h1 {
color: blue;
margin: 0 0 .5em;
}
main {
padding: 1em 2em;
}
label {
float: left;
width: 10em;
margin-right: 1em;
}
input {
margin-bottom: .5em;
}
#convert {
width: 10em;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Convert Temperatures</title>
<link rel="stylesheet" href="styles.css">
<script src="convert_temp.js"></script>
<script src="jquery-3.4.1.min.js"></script>
</head>
<body>
<main>
<h1>Convert temperatures</h1>
<input type="radio" name="conversion_type" id="to_celsius" checked>Fahrenheit to Celsius<br>
<input type="radio" name="conversion_type" id="to_fahrenheit">Celsius to Fahrenheit<br><br>
<label id="degree_label_1">Enter F degrees:</label>
<input type="text" id="degrees_entered" ><br>
<label id="degree_label_2">Degrees Celsius:</label>
<input type="text" id="degrees_computed" disabled><br>
<label> </label>
<input type="button" id="convert" value="Convert" /><br>
</main>
</body>
</html>
There are multiple issues in your code.
Looks like you are trying to use jQuery here, but in your case you are overriding the jQuery $ function with a custom function. So in effect you are not using jQuery here by calling the $ function but using pure javascript selectors
var $ = function(id) {
return document.getElementById(id);
};
With a function declaration as above, you can select elements only by Id and the Id should not be prefixed with #
$("#degree_label_1") won't work here
$("degree_label_1") will work.
So I suggest changing the $ function declaration to something like below.
var $ = function(selector) {
return document.querySelector(selector);
};
Here I changed document.getElementById -> document.querySelector so that selectors are more flexible (You can use any css selectors like "#id", ".classname" etc)
As we are not using jQuery here, the below code will not work. In jQuery, its correct but there are syntax differences in accessing the dom in plain javascript
$("#to_fahrenheit").val() == "true"
One way to implement the same is..
Assign values to the radio button inputs
<input
type="radio"
name="conversion_type"
id="to_celsius"
value="f_to_c"
checked
/>Fahrenheit to Celsius<br />
<input
type="radio"
name="conversion_type"
id="to_fahrenheit"
value="c_to_f"
/>Celsius to Fahrenheit<br />
and check the value
$("#to_fahrenheit").value == "c_to_f"
Same applies to the below line. There's a typo as well (Missed an e in degree_label_1)
$("#degree_labl_1").text("Enter F degrees")
should be changed to
$("#degree_label_1").textContent = "Enter F degrees"
Complete code would look like below.
"use strict";
var $ = function(id) {
return document.querySelector(id);
};
var clearTextBoxes = function() {
$("#degrees_entered").value = "";
$("#degrees_computed").value = "";
};
window.onload = function() {
$("#to_celsius").onclick = toCelsius;
$("#to_fahrenheit").onclick = toFahrenheit;
$("#convert").onclick = convert;
$("#degrees_entered").focus();
};
// Change the text of label 1 and 2 when the radio 'Celsius to Fahrenheit' is selected and clears all other inputs
var toFahrenheit = function() {
if ($("#to_fahrenheit").value == "c_to_f") {
$("#degree_label_1").textContent = "Enter C degrees";
$("#degree_label_2").textContent = "Degrees Fahrenheit";
clearTextBoxes();
}
};
// Change the text of label 1 and 2 when the radio 'Fahrenheit to Celsius' is selected and clears all other inputs
var toCelsius = function() {
if ($("#to_celsius").value == "f_to_c") {
$("#degree_label_1").textContent = "Enter F degrees";
$("#degree_label_2").textContent = "Degrees Celsius";
clearTextBoxes();
}
};
var convert = function() {
var conversiontype = $(
'[name="conversion_type"]:checked'
).value;
var enteredValue = Number($("#degrees_entered").value);
if (conversiontype === "f_to_c") {
$("#degrees_computed").value = ((enteredValue - 32) * 5) / 9;
} else {
$("#degrees_computed").value = (enteredValue * 9) / 5 + 32;
}
};
body {
font-family: Arial, Helvetica, sans-serif;
background-color: white;
margin: 0 auto;
width: 450px;
border: 3px solid blue;
}
h1 {
color: blue;
margin: 0 0 0.5em;
}
main {
padding: 1em 2em;
}
label {
float: left;
width: 10em;
margin-right: 1em;
}
input {
margin-bottom: 0.5em;
}
#convert {
width: 10em;
}
<h1>Convert temperatures</h1>
<input
type="radio"
name="conversion_type"
id="to_celsius"
value="f_to_c"
checked
/>Fahrenheit to Celsius<br />
<input
type="radio"
name="conversion_type"
id="to_fahrenheit"
value="c_to_f"
/>Celsius to Fahrenheit<br /><br />
<label id="degree_label_1">Enter F degrees:</label>
<input type="text" id="degrees_entered" /><br />
<label id="degree_label_2">Degrees Celsius:</label>
<input type="text" id="degrees_computed" disabled /><br />
<label> </label>
<input type="button" id="convert" value="Convert" /><br />
If you want to use jQuery, you should remove below function declaration
var $ = function(id) {
return document.getElementById(id);
};
And modify your code as follows.
"use strict";
var clearTextBoxes = function() {
$("#degrees_entered").val("");
$("#degrees_computed").val("");
};
window.onload = function() {
$("#to_celsius").on("click", toCelsius);
$("#to_fahrenheit").on("click", toFahrenheit);
$("#convert").on("click", convert);
$("#degrees_entered").focus();
};
// Change the text of label 1 and 2 when the radio 'Celsius to Fahrenheit' is selected and clears all other inputs
var toFahrenheit = function() {
if ($("#to_fahrenheit").val() == "c_to_f") {
$("#degree_label_1").text("Enter C degrees");
$("#degree_label_2").text("Degrees Fahrenheit");
clearTextBoxes();
}
};
// Change the text of label 1 and 2 when the radio 'Fahrenheit to Celsius' is selected and clears all other inputs
var toCelsius = function() {
if ($("#to_celsius").val() == "f_to_c") {
$("#degree_label_1").text("Enter F degrees");
$("#degree_label_2").text("Degrees Celsius");
clearTextBoxes();
}
};
var convert = function() {
var conversiontype = $(
'[name="conversion_type"]:checked'
).val();
var enteredValue = Number($("#degrees_entered").val());
if (conversiontype === "f_to_c") {
$("#degrees_computed").val(((enteredValue - 32) * 5) / 9);
} else {
$("#degrees_computed").val((enteredValue * 9) / 5 + 32);
}
};
body {
font-family: Arial, Helvetica, sans-serif;
background-color: white;
margin: 0 auto;
width: 450px;
border: 3px solid blue;
}
h1 {
color: blue;
margin: 0 0 0.5em;
}
main {
padding: 1em 2em;
}
label {
float: left;
width: 10em;
margin-right: 1em;
}
input {
margin-bottom: 0.5em;
}
#convert {
width: 10em;
}
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<h1>Convert temperatures</h1>
<input type="radio" name="conversion_type" id="to_celsius" value="f_to_c" checked />Fahrenheit to Celsius<br />
<input type="radio" name="conversion_type" id="to_fahrenheit" value="c_to_f" />Celsius to Fahrenheit<br /><br />
<label id="degree_label_1">Enter F degrees:</label>
<input type="text" id="degrees_entered" /><br />
<label id="degree_label_2">Degrees Celsius:</label>
<input type="text" id="degrees_computed" disabled /><br />
<label> </label>
<input type="button" id="convert" value="Convert" /><br />
I'm having an issue calculating the difference of two variables that should change depending on input values and number of inputs.
The jQuery works fine adding/subtracting buttons it's the peoplePaid() function that I've been dealing with.
I'm trying to write the difference (.difference) of paidTotal minus each input of pCheck.
So the first question is how do I get the value for difference (paidTotal - pCheck) to write to .difference for each input on the page.
And if I have to loop iy what may need to be done.
Thank you!
$(document).ready(function () {
var maxFields = 20;
var addButton = $('#plusOne');
var deleteButton = $('#minusOne');
var wrapper = $('#userNumbers');
var fieldInput = '<div><input type="text" name="persons" class="persons"/></div>';
var x = 1;
$(addButton).click(function () {
if (x < maxFields) {
x++;
$(wrapper).append(fieldInput);
}
});
$(deleteButton).click(function (e) {
e.preventDefault();
var myNode = document.getElementById("userNumbers");
i = myNode.childNodes.length - 1;
if (i >= 0) {
myNode.removeChild(myNode.childNodes[i]);
x--;
}
});
});
function peoplePaid() {
var checkTotal = parseFloat(document.getElementById('check').value);
var personsCheck = document.getElementsByClassName('persons');
var paidTotal = document.getElementById('paidTotal');
var serviceQuality = document.getElementById('serviceQuality').value;
var difference = document.getElementsByClassName('difference');
var pCheck = 0;
for (var i = 0; i < personsCheck.length; i += 1) {
pCheck += parseFloat(personsCheck[i].value);
}
paidTotal.innerHTML = (checkTotal * serviceQuality) - pCheck;
for (var i = 0; i < personsCheck.length; i += 1) {
checkDifference = parseFloat(paidTotal - pCheck).value;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Check Total</h3>
$ <input type="text" id="check" value="" />
<h3>Tip%</h3>
<select name="tip" id="serviceQuality">
<option disabled selected value="1">-- Choose an Option --</option>
<option value="1">0%</option>
<option value="1.06">6%</option>
<option value="1.15">15%</option>
<option value="1.2">20%</option>
<option value="1.3">30%</option>
</select>
<h3>Number of People: <span id="numberOfPeople"></span></h3>
<button type="button" onclick="plusOne()" id="plusOne">+</button>
<button type="button" onclick="minusOne()" id="minusOne">-</button>
<div>
<div id="userNumbers">
<input type="text" class="persons" name="person" />
<p class="difference">$</p>
</div>
</div>
<button onclick="peoplePaid()">Calculate</button>
<!--Paid Amount-->
<div>
<h3>Paid Amount: <span id="paidTotal"></span></h3>
</div>
Disscrepancies
There were some discrepancies that should be addressed:
(Major) There are two functions called by onclick event handlers:
<button type="button" onclick="plusOne()" id="plusOne">+</button>
<button type="button" onclick="minusOne()" id="minusOne">-</button>
First of all, a quick run of this Snippet logs errors about these functions not existing. Secondly, you should never use on-event handlers when using jQuery, it's like using paddle (on-event handlers) on a speed boat (event delegation using .on()).
(Minor) If you store jQuery Objects in variables, do not wrap those variables in $(...) because they already wrapped in $(...) when you declared them:
var addButton = $('#plusOne');
$(addButton).on('click',... // That is like doing this: $($('#plusOne'))
addButton.on('click',...... // This is the cleaner way or...
var $addButton = $('#plusOne');
$addButton.on('click'...... /* This is a common practice which serves as an obvious
reminder that the variable is a jQuery Object */
Plain JavaScript Array Methods
(Core) The solution is to collect all of the input.customer' by gathering the <input>s into a NodeList with .querySelctorAll() and then converting it into an array with Array.from():
var customers = Array.from(document.querySelectorAll('.customer'));
Next, use .map() to extract each of the <input>'s values, and then return them as an array:
var payments = customers.map(function(customer) {
return parseFloat(customer.value);
});
Finally, use .reduce() to add all of the values in the payments array into one number:
paidTotal = payments.reduce(function(total, number) {
return total + number;
});
Demo
var max = 20;
var count = 1;
var paidTotal = 0;
var customerQty = $('#totalCustomers');
var add = $('#add');
var group = $('.group');
var paid = `
<li>
<input type="number" class="customer" step='0.01'/>
<button type="button" class="remove">-</button>
</li>`;
add.on('click', function(e) {
if (count < max) {
count++;
group.append(paid);
} else {
return false;
}
customerQty.val(count);
});
group.on('click', '.remove', function() {
if (count > 0) {
count--;
var subtract = parseFloat($(this).prev('.customer').val()).toFixed(2);
var total = parseFloat($('#paidTotal').val()).toFixed(2);
var newTotal = parseFloat(total - subtract).toFixed(2);
$('#paidTotal').val(newTotal);
var due = parseFloat($('#balanceDue').val());
$('#balanceDue').val((due + parseFloat(subtract)).toFixed(2));
$(this).parent().remove();
} else {
return false;
}
customerQty.val(count);
});
$('#bill').on('input', totalPaid);
function totalPaid(e) {
var check = $('#check').val();
var tip = $('#tip').val();
var total = $('#paidTotal');
var due = $('#balanceDue');
var customers = Array.from(document.querySelectorAll('.customer'));
var payments = customers.map(function(customer) {
return parseFloat(customer.value);
});
//console.log('payments: '+payments);
paidTotal = payments.reduce(function(total, number) {
return total + number;
});
$('#amountDue').val(parseFloat(check * tip).toFixed(2));
//console.log('paidTotal: '+paidTotal);
total.val(parseFloat(paidTotal).toFixed(2));
due.val(parseFloat((check * tip) - total.val()).toFixed(2));
}
html {
font: 400 16px/1.5 Consolas;
}
body {
font-size: 1rem;
}
fieldset {
width: 490px;
}
button,
label,
select,
input,
output {
display: inline-block;
font: inherit;
line-height: 1.5;
}
label {
margin: 5px;
}
input {
width: 12ex;
text-align: center
}
button {
cursor: pointer;
}
output {
margin-left: -5px;
}
#totalCustomers {
font-size: 1.2rem;
color: blue;
}
#tip {
padding: 5px 0;
margin-left: -5px;
}
.tip {
margin-left: -2px;
}
.customers {
height: fit-content;
min-height: 60px;
}
.group {
margin: -8% 10px auto -25px;
padding-left: 1.5em;
width: 40%;
list-style-position: inside;
}
.group li {
padding-left: 0.1em;
}
.add {
transform: translate(105%, -15%);
}
/*
For debugging purposes only (Optional)
*/
.as-console-wrapper {
width: 250px;
min-height: 100%;
margin-left: 50%;
background: #000;
color: lime;
}
.as-console-row.as-console-row {
background: #000;
}
.as-console-row.as-console-row::after {
content: '';
padding: 0;
margin: 0;
border: 0;
width: 0;
}
<form id='bill'>
<fieldset class='total'>
<legend>Total Amount Due</legend>
$ <input type="number" id="check" value="" step='0.01' min='0.00'>
<label class='tip'>Tip%</label>
<select id="tip">
<option disabled selected value="">Pick</option>
<option value="1">0%</option>
<option value="1.06">6%</option>
<option value="1.15">15%</option>
<option value="1.2">20%</option>
<option value="1.3">30%</option>
</select>
<label>Amount Due: $
<output id="amountDue">0.00</output>
</label>
</fieldset>
<fieldset class='customers'>
<legend>Total Customers:
<output id="totalCustomers">1</output>
</legend>
<label class='add'> Add a Customer
<button type="button" id="add">+</button>
</label>
<ol class='group'>
<li>
<input type="number" class="customer" step='0.01' min='0.00' />
<button type="button" class="remove">-</button>
</li>
</ol>
</fieldset>
<fieldset class='grandTotal'>
<legend>Total Balance</legend>
<label>Paid Amount: $
<output id="paidTotal">0.00</output>
</label>
<br>
<label>Balance Due: $
<output id="balanceDue">0.00</output>
</label>
</fieldset>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I am trying to create a custom error message when a number which is too high or low is entered in the "size" element. However, I am unable to make this work. I am a beginner so a solution which involves the least changes to my existing code would be most appreciated.
function autoFillcost() {
var size = document.getElementById("size").value;
if (size <= 25)
document.getElementById("cost").value = "£100";
else if (size >= 26 && size <= 50)
document.getElementById("cost").value = "£200";
else
document.getElementById("cost").value = "£300";
}
function sizeValidate() {
var size = document.getElementById("size");
if (!size.checkValidity()) {
size.setCustomValidity("ERROR!");
} else {
size.setCustomValidity("");
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<body>
<form>
Group Size:<input type="number" min="6" max="200" id="size" onblur="autoFillcost();sizeValidate();" required>
<p>Cost:<input type="text" id="cost"></p>
<p id="demo"></p>
</form>
</body>
</html>
Sorry for digging, but it is possible, just report it after you set it.
Hopefully this helps others.
if (!size.checkValidity()) {
size.setCustomValidity("ERROR!");
size.reportValidity();
}
The problem with setCustomValidity is, that it does only work once you submit the form.
function autoFillcost() {
var size = document.getElementById("size").value;
if (size <= 25)
document.getElementById("cost").value = "£100";
else if (size >= 26 && size <= 50)
document.getElementById("cost").value = "£200";
else
document.getElementById("cost").value = "£300";
}
function sizeValidate() {
var size = document.getElementById("size");
if (!size.checkValidity()) {
size.setCustomValidity("ERROR!");
} else {
size.setCustomValidity("");
}
}
button {
padding:6px;
cursor:pointer;
}
input {
padding:5px;
border:1px solid #aaa;
box-shadow: 0px 0px 3px #ccc, 0 10px 15px #eee inset;
border-radius:2px;
}
input:valid {
background-color: white;
}
input:invalid {
background-color: lightpink;
}
<form>
Group Size:<input type="number" min="6" max="200" id="size" onblur="autoFillcost();sizeValidate();" required />
<p>Cost:<input type="text" id="cost"></p>
<p id="demo"></p>
<button type="submit">Submit</button>
</form>
I've been researching for a few days methods of controlling UI with checkboxes and with the help of some members on Stack' I've come really quite far. But my balding doesn't quite stop yet. I've been trying to further tweak my code snippet, by including a numeric value alongside my UI controller. (This value will be of use later inside the web-java applet.)
For example, when a checkbox is checked var total is ammended from 0 to 30. If a Checkbox is unchecked the value returns to '0'.
(Main Build JS Fiddle),
(Checkbox Example).
The second fiddle allows the use of data attributes, however these will need to be injected into the HTML via, JS. As like before I have 'NO' access to the CSS or HTML source files.
(Original Post)
- This post is a follow on from another question asked here on stack, due to the nature of the question changing, and the comments getting fairly confusing I was asked to open a new thread.
Below I'll post two snippets, one is of the original build, built with the aid of user #acontell. The other is an example of the type of result I am after, built with the aid of, user #Rajesh. Link to (Example Source).
The Base Build
// Control UI...
(function(domElements, cbState) {
// Number increment
var total = 0 + ' mm';
document.getElementById('adjvar').value = total;
function clickCallback() {
toggleElements(this.className);
}
function toggleElements(className, initialShow) {
var checkNumber = ((/ editoropt(\d*) /).exec(className))[1],
checkBox = document.getElementById('checkboxopt' + checkNumber),
division = document.querySelectorAll('.editoraccvar' + checkNumber)[0],
isShown = initialShow === undefined ? window.getComputedStyle(division).display === 'none' : initialShow;
division.style.display = isShown ? 'block' : 'none';
checkBox.checked = isShown;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// increment count...
var val = 30;
total += (+val * (checkBox.checked ? 1 : -1));
document.getElementById('adjvar').value = total + ' mm';
document.getElementsByClassName('adjvar').value = checkBox.checked ? val : 0 + ' mm';
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
}
domElements
.filter(function(el) {
return el.className.indexOf('editoropt') !== -1;
})
.forEach(function(el, index) {
el.addEventListener('click', clickCallback, false);
toggleElements(el.className, cbState[index]);
});
})([].slice.call(document.querySelectorAll('.seq-box-form-field')), [false, false]);
// Default Checked...
if (document.getElementById('checkboxopt').checked) {
// do nothing
} else {
document.getElementById('checkboxopt').click();
}
// inject style
function ctSe() {
var css = "input[type='checkbox'] { float:left; margin-right: 1em !important;}",
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
console.log(head)
console.log(style)
console.log(css)
};
ctSe();
.editoraccvar {
width: 300px;
background: #f0f;
padding: .5em;
}
.editoropt {
width: 300px;
background: #0f0;
padding: .5em;
}
.editoraccvar1 {
width: 300px;
background: #0ff;
padding: .5em;
}
.editoropt1 {
width: 300px;
background: #ff0;
padding: .5em;
}
textarea {
display: block;
width: 95%;
resize: none;
padding: .5em;
}
<!-- I'm trying to hide & show this entire division... -->
<div class="seq-box-form-field field-summernote editoraccvar ">
<label for="accvar1">Ground Floor Info</label>
<div class="clearfix"></div>
<textarea id="richaccvar1" name="richaccvar1" class="summernote"></textarea>
<input type="hidden" name="accvar1" id="accvar1" value="" />
</div>
<!-- Using only what the system has supplied. -->
<div class="seq-box-form-field editoropt ">
<label for="opt1"><span style="padding-right: 10px; vertical-align: 1px;">Ground Floor </span>
<input type="checkbox" name="checkboxopt" id="checkboxopt" value="true" checked="true" />
<input type="hidden" name="opt1" id="opt1" value="true" />
</label>
</div>
<!-- Secondary Division -->
<div class="seq-box-form-field field-summernote editoraccvar1 ">
<label for="accvar1">First Floor</label>
<div class="clearfix"></div>
<textarea id="richaccvar1" name="richaccvar1" class="summernote"></textarea>
<input type="hidden" name="accvar1" id="accvar1" value="" />
</div>
<!-- Secondary Checkbox -->
<div class="seq-box-form-field editoropt1 ">
<label for="opt1"><span style="padding-right: 10px; vertical-align: 1px;">First Floor </span>
<input type="checkbox" name="checkboxopt1" id="checkboxopt1" value="true" checked="true" />
<input type="hidden" name="opt1" id="opt1" value="true" />
</label>
</div>
<input name="adjvar" id="adjvar" readonly>
The Example
(function() {
var total = 0;
function calculate(index) {
var el = document.getElementsByClassName('checkbox-input')[index];
var val = el.getAttribute("data-value");
total += (+val * (el.checked ? 1 : -1));
document.getElementById('pnvar').value = total;
document.getElementsByClassName('pnvar')[index].value = el.checked ? val : 0;
}
function registerEvents() {
var cbs = document.querySelectorAll('[type="checkbox"]');
[].forEach.call(cbs, function(cb, i) {
cb.addEventListener("click", function() {
calculate(i);
});
});
document.getElementById('pnvar').addEventListener('keydown', function(event) {
if (event.keyCode == 13) {
event.preventDefault();
return false;
}
})
}
window.addEventListener('load', function() {
registerEvents();
calculate(0)
})
})()
.editoropt {
font-family: Calibri, sans-serif;
width: 160px;
background: #f8f8ff;
padding: .5em;
border: solid 1px #ddd;
}
#checkboxopt {
float: left;
margin-right: 1em;
margin-top: 4px;
}
#checkboxopt1 {
float: left;
margin-right: 1em;
margin-top: 4px;
}
.pnvar {
width: 95%;
}
input:-moz-read-only {
/* For Firefox */
background-color: transparent;
border: none;
border-width: 0px;
}
input:read-only {
background-color: transparent;
border: none;
border-width: 0px;
}
<div class="seq-box-form-field editoropt ">
<label for="opt1">
<span style="padding-right: 10px; vertical-align: 1px;">Default 80mm </span>
<input type="checkbox" class="checkbox-input" data-value="80" name="checkboxopt" id="checkboxopt" value="true" checked />
<input type="hidden" name="opt1" id="opt1" value="true" />
</label>
</div>
<div class="seq-box-form-field editoropt ">
<label for="opt1">
<span style="padding-right: 10px; vertical-align: 1px;">Add 30mm </span>
<input type="checkbox" class="checkbox-input" name="checkboxopt1" data-value="30" id="checkboxopt1" value="true" />
<input type="hidden" name="opt2" id="opt2" value="true" />
</label>
</div>
<div class="editoropt">
<input id="pnvar" name="pnvar" placeholder="Null" onkeydown="" value="" class="required" type="text">
<input name="adjvar" class="pnvar" id="adjvar" readonly value="0">
<input name="adjvar" class="pnvar" id="adjvar2" readonly value="0">
</div>
As I mentioned in my previous post, I'm not a JS Whizz and I'm just finding my feet, however I am abitious to learn and further my knowledge. Any assistance would be greatly appreciated.
Note : All tags, classes and names, must remain the same for consistancy with another application.
I might be mistaken but I think that this two lines of code:
// Default Checked...
if (document.getElementById('checkboxopt').checked) {
// do nothing
} else {
document.getElementById('checkboxopt').click();
}
Could be avoided if you passed [true, false] as the initial states of the checkboxes:
([].slice.call(document.querySelectorAll('.seq-box-form-field')), [true, false]);
I might be wrong, you might be doing something else or the state of the page could require that click, I don't know.
Going back to the issue, if you want to increase/decrease by 30 when the checkbox is checked/unchecked, you could do as follows:
Create a function that retrieves the value of the input an updates it with a quantity added to it. The value of the input is a string of the form 'x mm' so a bit of tinkering is necessary to get the integer part of the value.
function updateInputValue(n) {
var actual = +document.getElementById('adjvar').value.split(' mm')[0] || 0;
document.getElementById('adjvar').value = (actual + n) + ' mm';
}
Inside toggleElement call this function in order to update the input value.
var increment = isShown ? 30 : -30;
updateInputValue(initialShow === undefined ? increment : +initialShow * 30);
It gets a bit complicated because you have to control the initial state of the inputs, but it's not that hard: if it's the initial state, initialShow is different from undefined so we transform the value (it's a boolean) into a number a multiply it by 30 (when it's checked, it'd be 1 * 30, when it's unchecked it'd be 0 * 30). When it's not the initial state, we increment/decrement depending on whether it's checked or not.
And here's the fiddle (I also commented out the part that clicked the checkbox). Hope it helps.