Range Slider made on JS and HTML - javascript

I have created a code with 4 range slider that displays only its total in "$" symbol.
This total must not exceed 5 symbols in all 4 sliders.
The objective is that the customer will be able to have a visual appercus without knowing the amount how much his project will cost him.
Here is the code I have done so far.
<div id="container">
<label for="slider1">Titre 1</label>
<input type="range" id="slider1" min="0" max="5" value="0">
<br>
<label for="slider2">Titre 2</label>
<input type="range" id="slider2" min="0" max="5" value="0">
<br>
<label for="slider3">Titre 3</label>
<input type="range" id="slider3" min="0" max="5" value="0">
<br>
<label for="slider4">Titre 4</label>
<input type="range" id="slider4" min="0" max="5" value="0">
<br>
<div id="total">Total: <span id="dollar-signs"></span></div>
</div>
<style>
#container {
display: flex;
flex-direction: column;
}
label {
font-weight: bold;
}
#total {
font-weight: bold;
}
#total.exceeded {
color: red;
}
</style>
<script>
const sliders = document.querySelectorAll("#container input[type=range]");
function updateTotal() {
let total = 0;
sliders.forEach(slider => {
total += Number(slider.value);
});
const totalElement = document.getElementById("total");
const dollarSigns = document.getElementById("dollar-signs");
dollarSigns.innerHTML = "";
for (let i = 0; i < total; i++) {
if (i < 5) {
dollarSigns.innerHTML += "$";
}
}
if (total > 5) {
totalElement.classList.add("exceeded");
} else {
totalElement.classList.remove("exceeded");
}
}
sliders.forEach(slider => {
slider.addEventListener("input", updateTotal);
});
updateTotal();
</script>
I would like someone to help me debug my script to allow the 4 slider to display a maximum of 5 $ sybols.
Currently it does it but not correctly if my 4 sliders are at their maximum it must be 5 symbols.

Related

I have these 2 tonnage calculators. The first one is working great. How can I fix the second one? Is something wrong with my Javascript?

I would also like if I could have the value printed on the screen instead of showing up as an alert. For some reason my code was working when I only had the 1 calculator on the screen but when I tried adding a second one and modifying the javascript a little bit so the second one works as well both stopped working.
THANKS!
sum = {
"al": 12,
"mm": 20,
"hm": 30,
}
let val;
window.addEventListener("load", function() { // when page loads
document.getElementById("tensile").addEventListener("click", function(e) {
var tgt = e.target; // what was clicked
if (tgt.name == "size") { // is it one of the radios?
val = tgt.value; // save the value once (DRY principle)
}
})
$('.ck').click(function() {
var a = parseFloat($('.n1').val());
var b = parseFloat($('.n2').val());
var z = 3.14;
var c = a * b * z * sum[val];
alert(c);
})
})
sum = {
"al1": 12,
"mm1": 20,
"hm1": 30,
}
let val1;
window.addEventListener("load", function() { // when page loads
document.getElementById("tensile1").addEventListener("click", function(g) {
var tgt1 = g.target; // what was clicked
if (tgt1.name == "size") { // is it one of the radios?
val1 = tgt1.value; // save the value once (DRY principle)
}
})
$('.ck1').click(function() {
var a1 = parseFloat($('.n3').val());
var b1 = parseFloat($('.n4').val());
var c1 = parseFloat($('.m2').val());
var z1 = 3.14;
var d1 = a1 * b1 * z1 * sum[val1];
alert(d1);
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<h1>ROUND HOLE</h1>
Diameter<input type="text" class="n1" /><br /> Metal Thickness<input type="text" class="n2" /><br />
<h3> Select Metal </h3>
<form id="tensile">
<input type="radio" name="size" value="al">Alum
<br>
<input type="radio" name="size" value="mm">Mild Metal<br>
<input type="radio" name="size" value="hm"> Heavy Metal<br>
<br>
</form>
<hr />
<input type="button" value="Add" class="ck" />
</div>
<div>
<h1>RECTANGLE HOLE</h1>
Length<input type="text" class="n3" /><br />
width<input type="text" class="n4" /><br />
Metal Thickness<input type="text" class="m2" /><br />
<h3> Select Metal </h3>
<form id="tensile1">
<input type="radio" name="size" value="al1">Alum
<br>
<input type="radio" name="size" value="mm1">Mild Metal<br>
<input type="radio" name="size" value="hm1"> Heavy Metal<br>
<br>
</form>
<hr />
<input type="button" value="Add" class="ck1" />
</div>
Your sum object is declared twice. The second declaration overwrites the first, so the keys needed for the first calculator are lost.
The first one throw an error because you reassigned sum. For instance the first one looks for the value of al key but there isn't anymore because you reassigned it, there is al1. So you should assign sum once and it should be as following:
let sum = {
"al": 12,
"mm": 20,
"hm": 30,
"al1": 12,
"mm1": 20,
"hm1": 30,
}
Here is the working example:
let sum = {
"al": 12,
"mm": 20,
"hm": 30,
"al1": 12,
"mm1": 20,
"hm1": 30
}
let val;
window.addEventListener("load", function() { // when page loads
document.getElementById("tensile").addEventListener("click", function(e) {
var tgt = e.target; // what was clicked
if (tgt.name == "size") { // is it one of the radios?
val = tgt.value; // save the value once (DRY principle)
}
})
$('.ck').click(function() {
var a = parseFloat($('.n1').val());
var b = parseFloat($('.n2').val());
var z = 3.14;
var c = a * b * z * sum[val];
alert(c);
})
})
let val1;
window.addEventListener("load", function() { // when page loads
document.getElementById("tensile1").addEventListener("click", function(g) {
var tgt1 = g.target; // what was clicked
if (tgt1.name == "size") { // is it one of the radios?
val1 = tgt1.value; // save the value once (DRY principle)
}
})
$('.ck1').click(function() {
var a1 = parseFloat($('.n3').val());
var b1 = parseFloat($('.n4').val());
var c1 = parseFloat($('.m2').val());
var z1 = 3.14;
var d1 = a1 * b1 * c1 * z1 * sum[val1];
alert(d1);
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<h1>ROUND HOLE</h1>
Diameter<input type="text" class="n1" /><br /> Metal Thickness<input type="text" class="n2" /><br />
<h3> Select Metal </h3>
<form id="tensile">
<input type="radio" name="size" value="al">Alum
<br>
<input type="radio" name="size" value="mm">Mild Metal<br>
<input type="radio" name="size" value="hm"> Heavy Metal<br>
<br>
</form>
<hr />
<input type="button" value="Add" class="ck" />
</div>
<div>
<h1>RECTANGLE HOLE</h1>
Length<input type="text" class="n3" /><br />
width<input type="text" class="n4" /><br />
Metal Thickness<input type="text" class="m2" /><br />
<h3> Select Metal </h3>
<form id="tensile1">
<input type="radio" name="size" value="al1">Alum
<br>
<input type="radio" name="size" value="mm1">Mild Metal<br>
<input type="radio" name="size" value="hm1"> Heavy Metal<br>
<br>
</form>
<hr />
<input type="button" value="Add" class="ck1" />
</div>
the corect way to code that (IMHO) :
const
myForm = document.forms['my-form']
, sDigits = new Intl.NumberFormat('en-US', { maximumFractionDigits: 4, minimumFractionDigits: 2 })
, Metal = { al: 12, mm: 20, hm: 30 }
;
myForm['bt-control-round'].onclick = () =>
{
let val = myForm['diameter-round'].valueAsNumber
* myForm['thickness-round'].valueAsNumber
* 3.14
* Metal[ myForm['metal-round'].value ]
;
// alert( `round hole:\n ${val.toFixed(4)}` )
myForm['out-control-round'].value = isNaN(val) ? 'bad entrie(s)' : sDigits.format(val)
}
myForm['bt-control-rect'].onclick = () =>
{
let val = myForm['length-rect'].valueAsNumber
* myForm['width-rect'].valueAsNumber
* myForm['thickness-rect'].valueAsNumber
// * 3.14
* Metal[ myForm['metal-rect'].value ]
;
// alert( `rectangle hole:\n ${val.toFixed(4)}` )
myForm['out-control-rect'].value = isNaN(val) ? 'bad entrie(s)' : sDigits.format(val)
}
myForm.onsubmit = evt => { evt.preventDefault() } // disable submit
form {
font-family : 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size : 14px;
}
form legend {
text-transform : capitalize;
padding : 0 1em;
}
form fieldset {
margin-top : 1em;
width : 20em;
}
form .backLine,
form .backLinePlus,
form .backLinePlus * {
display : block;
float : left;
clear : both;
}
form label.cVal {
margin-top : .7em;
}
form label.cVal span {
font-size : .9em;
padding-right : .2em;
font-weight : bold;
}
form h5 {
margin : 1em 0 .2em 0;
}
form label.cCheck input {
vertical-align : text-bottom;
}
form output {
font-size : 1.4em;
font-weight : bold;
text-align : center;
background : lightblue;
padding : .3em;
box-sizing : border-box;
width : 100%;
margin : .3em 0;
}
<form name="my-form">
<fieldset>
<legend>round hole</legend>
<label class="backLinePlus cVal">
<span>Diameter :</span>
<input name="diameter-round" type="number" value="0" min="0" step="any" >
</label>
<label class="backLinePlus cVal">
<span>Metal Thickness :</span>
<input name="thickness-round" type="number" value="0" min="0" step="any" >
</label>
<h5 class="backLine">Select Metal</h5>
<label class=" cCheck backLine">
<input name="metal-round" value="al" type="radio" checked >
<span>Alum</span>
</label>
<label class="cCheck backLine">
<input name="metal-round" value="mm" type="radio" >
<span>Mild Metal</span>
</label>
<label class="cCheck backLine">
<input name="metal-round" value="hm" type="radio" >
<span>Heavy Metal</span>
</label>
<h5 class="backLine"> </h5>
<button type="button" name="bt-control-round" class="backLine">⚙ calc</button>
<output name="out-control-round" class="backLine">...</output>
</fieldset>
<fieldset>
<legend>rectangle hole</legend>
<label class="backLinePlus cVal">
<span>length :</span>
<input name="length-rect" type="number" value="0" min="0" step="any">
</label>
<label class="backLinePlus cVal">
<span>width :</span>
<input name="width-rect" type="number" value="0" min="0" step="any" >
</label>
<label class="backLinePlus cVal">
<span>Metal Thickness :</span>
<input name="thickness-rect" type="number" value="0" min="0" step="any" >
</label>
<h5 class="backLine">Select Metal</h5>
<label class=" cCheck backLine">
<input name="metal-rect" value="al" type="radio" checked >
<span>Alum</span>
</label>
<label class="cCheck backLine">
<input name="metal-rect" value="mm" type="radio" >
<span>Mild Metal</span>
</label>
<label class="cCheck backLine">
<input name="metal-rect" value="hm" type="radio" >
<span>Heavy Metal</span>
</label>
<h5 class="backLine"> </h5>
<button type="button" name="bt-control-rect" class="backLine">❏ calc</button>
<output name="out-control-rect" class="backLine">...</output>
</fieldset>
</form>

Prevent slider from jumping when value is changed

I have a slider that live-updates the value on a label tag to the right of it. What should I do to prevent it from "jumping" when the value goes from 1-digit value to 2-digits value? How can I give the label a fixed position so that it won't change the layout:
var range = document.getElementById('range');
range.addEventListener('input', rangeChange);
function rangeChange() {
label.innerHTML = this.value;
}
<label id="label">0</label>
<input id="range" type="range" value=0 min=0 max=100>
Either add width: 20px;display: inline-block; to the label.
Or
Add a wrapper around both the elements and give them display: flex; align-items: center; style and width to the label.
var range = document.getElementById('range');
range.addEventListener('input', rangeChange);
function rangeChange() {
label.innerHTML = this.value;
}
<div style="display: flex; align-items: center;">
<label id="label" style="width: 20px;">0</label>
<input id="range" type="range" value=0 min=0 max=100>
</div>
Option 1: Put label to right side of slider
var range = document.getElementById('range');
range.addEventListener('input', rangeChange);
function rangeChange() {
label.innerHTML = this.value;
}
<input id="range" type="range" value=0 min=0 max=100>
<label id="label">0</label>
Option 2: Zero padding:
var range = document.getElementById('range');
range.addEventListener('input', rangeChange);
function rangeChange() {
var val = +(this.value);
if (10 > val) {
val = '00' + val;
} else if (100 > val) {
val = '0' + val;
}
label.innerHTML = val;
}
<label id="label">000</label>
<input id="range" type="range" value=0 min=0 max=100>

Multiple object events for one function?

So I'm trying to make an html page with 3 sliders for the background (R,G,B)
I want each slider to call a function that changes the background on input, but I can't get it to work unless I rewrite the function for each event. Please bear with me, I'm a new coder and most of this is spaghetti
var red = document.getElementById("red"); //slider values
var routput = document.getElementById("reddemo"); //display values
routput.innerHTML = red.value; //for function
var green = document.getElementById("green");
var goutput = document.getElementById("greendemo");
goutput.innerHTML = green.value;
var blue = document.getElementById("blue");
var boutput = document.getElementById("bluedemo");
boutput.innerHTML = blue.value;
red.oninput && blue.oninput && green.oninput = function() {
//this is what I want to do; string all of these oninputs together... obviously this way doesn't work
var x = Math.round([Number(red.value) + Number(blue.value) + Number(green.value)] / 3);
//this is for later, the text color in body changes to white when color values get too low
routput.innerHTML = Math.round(this.value);
boutput.innerHTML = Math.round(this.value);
goutput.innerHTML = Math.round(this.value);
document.body.style.backgroundColor = "rgb(" + routput.innerHTML + "," + routput.innerHTML + "," + routput.innerHTML + ")";
if (x < 127.5) {
document.body.style.color = "rgb(255,255,255)";
} else {
document.body.style.color = "rgb(0,0,0)";
}
}
<p>Red</p>
<div class="slidecontainer">
<input type="range" min="0" max="255" value="255" class="slider" id="red">
<p>Value: <span id="reddemo"></span></p>
</div>
<p>Green</p>
<div class="slidecontainer">
<input type="range" min="0" max="255" value="255" class="slider" id="green">
<p>Value: <span id="greendemo"></span></p>
</div>
<p>Blue</p>
<div class="slidecontainer">
<input type="range" min="0" max="255" value="255" class="slider" id="blue">
<p>Value: <span id="bluedemo"></span></p>
</div>
Functions in JavaScript are first-class citizens, meaning you can treat a function as a variable:
var changeBackground = function () {…};
red.oninput = changeBackground;
blue.oninput = changeBackground;
…
The other solution - Makhiel's is also correct is:
red.oninput = blue.oninput = green.oninput = function() {
&& is 'logical and' in JavaScript: it always turns into true or false. Though "Set red.oninput and blue.oninput to the same function" works in english, the and in English doesn't translate to the and in Javascript.
It's pretty straight forward using the HTMLFormControlsCollection API.
Changed the elements into more semantic as well as functional form control elements: <form>, <output>, <fieldset>,<legend>, and <label>. Used Template Literals to get all 3 values to mix in one value.
The key to reducing the number of functions and events is to use Event Delegation by having an element that is a common ancestor to the ranges, listen for the input event. Then by referencing the Event.target we can determine exactly which range is interacting with the user.
BTW in this case, there's no need to convert any values to a number because the value the CSS takes as a RGB color is actually a string that has chars that represent numbers.
Update
Added a second Demo that does the same thing as Demo 1, but with very minimal code by using On Event Attributes. Although the use of them is strongly discouraged I've seen a growing trend of it's use in current but minor code such as this.
Demo 1
Details commented in Demo
form {
display: flex;
flex-flow: column wrap;
height: 100vh;
}
.slidecontainer {
width: 40%;
height: 15vh
}
output {
transform: translate(5px, -7px);
display: inline-block;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form id='rgb'>
<fieldset class="slidecontainer">
<legend>Red</legend>
<input type="range" min="0" max="255" value="255" class="slider" id="red0">
<output id="redO"></output>
</fieldset>
<fieldset class="slidecontainer">
<legend>Green</legend>
<input type="range" min="0" max="255" value="255" class="slider" id="grn0">
<output id="grnO"></output>
</fieldset>
<fieldset class="slidecontainer">
<legend>Blue</legend>
<input type="range" min="0" max="255" value="255" class="slider" id="blu0">
<output id="bluO"></output>
</fieldset>
</form>
<script>
//Reference the form
var form = document.forms.rgb;
//Reference all of form's form controls
var rgb = form.elements;
//Register input event on form
form.addEventListener('input', composeColor);
// Callback function pass Event Object
function composeColor(e) {
//if the node interacting with user is type=range...
if (e.target.type === "range") {
// Reference active range
var rng = e.target;
// Get range's "little brother" output
var viewVal = rng.nextElementSibling;
// Sync their values
viewVal.value = rng.value;
// Collect the values of all ranges then interpolate them
// into a template literal.
// The TL is the color of body
document.body.style.background = `rgb(${red0.value}, ${grn0.value}, ${blu0.value})`;
} else return false;
}
</script>
</body>
</html>
Demo 2
On Event Attribute
form {
display: flex;
flex-flow: column wrap;
height: 100vh;
}
.slidecontainer {
width: 40%;
height: 15vh
}
output {
transform: translate(5px, -7px);
display: inline-block;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form id='rgb' oninput="document.body.style.background = `rgb(${red0.value},${grn0.value}, ${blu0.value})`">
<fieldset class="slidecontainer">
<legend>Red</legend>
<input type="range" min="0" max="255" value="255" class="slider" id="red0" oninput='redO.value = this.value'>
<output id="redO" for='red0'></output>
</fieldset>
<fieldset class="slidecontainer">
<legend>Green</legend>
<input type="range" min="0" max="255" value="255" class="slider" id="grn0" oninput='grnO.value = this.value'>
<output id="grnO" for='grn0'></output>
</fieldset>
<fieldset class="slidecontainer">
<legend>Blue</legend>
<input type="range" min="0" max="255" value="255" class="slider" id="blu0" oninput='bluO.value = this.value'>
<output id="bluO" for='blu0'></output>
</fieldset>
</form>
<script>
</script>
</body>
</html>

Display values of multiple input type range in one page

I'm trying to display values of every slider I have on my page, this is my code so far:
var i = 0;
var st = 'slider';
var ot = 'output';
var s = '';
var o = '';
for (var x = 0; x < 3; x++) {
i++;
s = st+i;
o = ot+i;
var s = document.getElementById("range"+i);
var o = document.getElementById("limit"+i);
o.innerHTML = s.value;
s.oninput = function() {
o.innerHTML = this.value;
}
}
<div id="slidecontainer">
<input type="range" min="2" max="50" value="20" class="slider" id="range1" >
<label>You chose <span id="limit1"></span></label>
</div>
<div id="slidecontainer">
<input type="range" min="2" max="50" value="20" class="slider" id="range2" >
<label>You chose <span id="limit2"></span></label>
</div>
<div id="slidecontainer">
<input type="range" min="2" max="50" value="20" class="slider" id="range3" >
<label>You chose <span id="limit3"></span></label>
</div>
It's only changing the last value when I move any slider, I want to display the value of each slider respectively. I'm using a loop in my JavaScript code because I have more than 20 sliders and I don't want to write a function for each of them unless that is the only way of doing it. Any suggestions?
The problem you are having is related to variable scope. There is only one variable named o, each iteration of the loop changes this variable. So when the
oninput function is evaluated o equals the last value you set it to equal. The current value of o is not "saved" in the function definition.
See https://www.w3schools.com/js/js_scope.asp for more information.
See solution below, here I find the limit in each call to the function.
function updateLabel() {
var limit = this.parentElement.getElementsByClassName("limit")[0];
limit.innerHTML = this.value;
}
var slideContainers = document.getElementsByClassName("slidecontainer");
for (var i = 0; i < slideContainers.length; i++) {
var slider = slideContainers[i].getElementsByClassName("slider")[0];
updateLabel.call(slider);
slider.oninput = updateLabel;
}
<div class="slidecontainer">
<input type="range" min="2" max="50" value="20" class="slider">
<label>You chose <span class="limit"></span></label>
</div>
<div class="slidecontainer">
<input type="range" min="2" max="50" value="20" class="slider">
<label>You chose <span class="limit"></span></label>
</div>
<div class="slidecontainer">
<input type="range" min="2" max="50" value="20" class="slider">
<label>You chose <span class="limit"></span></label>
</div>

Multiply total orders to quantity of order in jquery

I have a jquery that multiplies the price to quantity. Now I wanted to multiply the total of that to how many orders a costumer would place. Where would I insert my multiplication code? Here's how i envisioned the equation would be total=(price*quantity)*numberoforders. Here's a jfiddle of what I cant eloquently explain
Here's my code:
HTML
<form>
<ul>
<li>
<label>
<input type="checkbox" name="drink[]" class="drink" value="DrinkName1" data-price="12" /> Sample Item
<input min="0" max="5" type="number" class="quantity" name="quantity" value="1" />
</label>
</li>
<li>
<label>
<input type="checkbox" name="drink[]" class="drink" value="DrinkName2" data-price="6" /> Sample Item
<input min="0" max="5" type="number" class="quantity" name="quantity" value="1" />
</label>
</li>
<li>
<label>
<input type="checkbox" name="drink[]" class="drink" value="DrinkName3" data-price="4" /> Sample Item
<input min="0" max="5" type="number" class="quantity" name="quantity" value="1" />
</label>
</li>
<li>
<label>
Quantity of Orders
<input min="0" max="5" type="number" class="totalquant" name="quantity" value="1" />
</label>
</li>
</ul>
</form>
<p>Total</p>
<div id="totalDiv">0</div>
Jquery
$('.quantity, .drink').change(calculateTotal);
function calculateTotal() {
var $form = $(this).closest('form'), total = 0;
$form.find('.drink:checked').each(function() {
total += $(this).data('price') * parseInt($(this).next('.quantity').val() || 0, 10);
});
$('#totalDiv').text(total)* parseInt($(this).siblings('.totalquant').val() || 0, 10);
}
Appreciate all the help
I've made some changes on your code here https://jsfiddle.net/k91d23p6/3/
Basically, you have to multiply the total by the totalQuant after the forEach.
//query the DOM once, instead of on every change
var $form = $('form'); //on a real app it would be better to have a class or ID
var $totalQuant = $('.totalquant', $form);
var totalDiv = $('#totalDiv');
$('.quantity, .drink, .totalquant', $form).change(calculateTotal);
function calculateTotal() {
var total = 0;
$form.find('.drink:checked').each(function() {
total += $(this).data('price') * parseInt($(this).next('.quantity').val() || 0, 10);
});
var totalQuant = total * parseInt( $totalQuant.val() || 0, 10);
totalDiv.text(totalQuant);
}

Categories

Resources