Multiple object events for one function? - javascript

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>

Related

How to reset JavaScript code when input value is changed?

I would like for the code to change its answer when I change the value of the input.
So let's say instead of 10, I would like it to tell me how much HP (health points) I will have at level 15. Is there any way I can do this? I'm not that experienced in Javascript.
So right now I coded it to default to 10 on all stats. My website tells me that at level 10, I have 895.4 hp. The only problem is that it won't stay at 15 when I try to press enter. It will just revert back to 10. Pretty much useless. Is there any way to keep that number 15 when I press enter?
var finalhp = 500;
let hpmultiplier = 1.06;
var hpvaluestring = document.querySelector('.hp').value;
var hpvalue = parseInt(hpvaluestring);
for (let i = 0; i < hpvalue; i++) {
var finalhp = finalhp * hpmultiplier
}
console.log(finalhp)
<form>
<div>
<input class="hp" id="amount" type="number" value="10" min="0" max="50" oninput="rangeInput.value=amount.value">
<input class="slider" id="rangeInput" type="range" value="10" min="0" max="50" oninput="amount.value=rangeInput.value">
</div>
</form>
Add a form submit event listener to the form element and prevent form submission there.
<form onsubmit="submitForm(event)">
<div>
<input class="hp" id="amount" type="number" value="10" min="0" max="50" oninput="rangeInput.value=amount.value">
<input class="slider" id="rangeInput" type="range" value="10" min="0" max="50" oninput="amount.value=rangeInput.value">
</div>
</form>
Add a submitForm function inside a script tag
function submitForm(event){
event.preventDefault();
var finalhp = 500;
let hpmultiplier = 1.06;
var hpvaluestring = document.querySelector('.hp').value;
var hpvalue = parseInt(hpvaluestring);
for (let i = 0; i < hpvalue; i++) {
var finalhp = finalhp * hpmultiplier
}
console.log(finalhp)
}
So mainly I'm just adding eventListeners to trigger the function calculateHP on input/slider value change. The function calculateHP contains the same logic that you shared. I did this so that the eventListeners can callback the function.
Try the following:
const input = document.querySelector('.hp')
const slider = document.querySelector('.slider')
slider.addEventListener('change', calculateHP)
input.addEventListener('change', calculateHP)
function calculateHP(){
let multiplier = 1.06
let level = Number(input.value)
let HP = 500
for(let i = 0; i<level; i++){
HP = HP * multiplier
}
return console.log(HP)
}
<div>
<label>Level: </label>
<input class="hp" id="amount" type="number" value="10" min="0" max="50" oninput="rangeInput.value=amount.value">
<input class="slider" id="rangeInput" type="range" value="10" min="0" max="50" oninput="amount.value=rangeInput.value">
</div>

Multiple Javascript functions embedded in html

I am trying to implement two sliders in HTML and use Javascript functions to update the indicator of the values of those sliders. I don't know how to structure the code for the output of each slider. I think there is a problem with the way that the Javascript codes are embedded. Does anyone know how I can solve this issue?
Purpose: Have two sliders with two separate indicators in HTML
Thanks!
<body>
<h1>Round Range Slider</h1>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50" class="slider" id="myRange">
<p>Value: <span id="demo"></span></p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50" class="slider" id="myRange1">
<p>Value1: <span id="demo1"></span></p>
</div>
</body>
<head>
<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;
slider.oninput = function() {
output.innerHTML = this.value;
}
</script>
<script>
var slider = document.getElementById("myRange1");
var output = document.getElementById("demo1");
output.innerHTML = slider.value;
slider.oninput = function() {
output.innerHTML = this.value;
}
</script>
</head>
Duplicating the code, taking into account the introduction of small changes - is bad.
I made you a js code with the forEach() method. This means that now you can control many input without having to write js logic for every.
Just replace your js code with this one:
let input = document.querySelectorAll('.slidecontainer input');
let result = document.querySelectorAll('.slidecontainer span');
input.forEach(function(input_current, index) {
input_current.oninput = function() {
result[index].innerHTML = this.value;
}
});
Declaring variables in separate script tags does not create two copies of the variable. You can declare a variable for each slider by giving them different names.
<body>
<h1>Round Range Slider</h1>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange">
<p>Value: <span id="demo"></span></p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange1">
<p>Value1: <span id="demo1"></span></p>
</div>
</body>
<head>
<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;
slider.oninput = function() {
output.innerHTML = this.value;
}
var slider1 = document.getElementById("myRange1");
var output1 = document.getElementById("demo1");
output1.innerHTML = slider1.value;
slider1.oninput = function() {
output1.innerHTML = this.value;
}
</script>
</head>
Better yet, use a loop:
<body>
<h1>Round Range Slider</h1>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange">
<p>Value: <span id="demo"></span></p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange1">
<p>Value1: <span id="demo1"></span></p>
</div>
</body>
<head>
<script>
let sliders = document.querySelectorAll(".slidecontainer");
sliders.forEach(slideContainer => {
// Get a reference to the children of the current container.
let sliderChild = slideContainer.children[0];
let spanChild = slideContainer.children[1].children[0];
// Attach an event listener to each slider.
sliderChild.oninput = () => spanChild.innerText = sliderChild.value;
// Initialize the label.
spanChild.innerText = sliderChild.value;
});
</script>
</head>

How do I showcase the selected value from a range selection?

I'm working on a Javascript RGB Color Picker and struggling with the front-end.
A RGB Color Picker results in a color that exists within the combination of three values (R,G,B), with each value having a range of 0 - 255.
This is my project so far, it allows an user to pick a combination from a range selection but it doesn't showcase the value that he picked.
<body>
<div class="picker">
Red <input type="range" min="0" max="255" step="1" id="red" value="115">
Green <input type="range" min="0" max="255" step="1" id="green" value="10">
Blue <input type="range" min="0" max="255" step="1" id="blue" value="162">
<div id="display"></div>
</div>
<script type="text/javascript">
var input = document.querySelectorAll("input");
for (var i = 0; i < input.length; i++) {
input[i].addEventListener("input",
function () {
var
red = document.getElementById("red").value,
green = document.getElementById("green").value,
blue = document.getElementById("blue").value;
var display = document.getElementById("display");
display.style.background = "rgb(" + red + ", " + green + ", " + blue + ")";
}
);
}
</script>
</body>
How do I showcase the selected value from the range selection so that the user knows the combination he is selecting?
I'm new to JS, HTML and CSS so I have no idea what I'm supposed to do.
By default, a div's size is 0 by 0. You just need to add some style to the display to give it some size, then the background will be visible:
<body>
<div class="picker">
Red <input type="range" min="0" max="255" step="1" id="red" value="115">
Green <input type="range" min="0" max="255" step="1" id="green" value="10">
Blue <input type="range" min="0" max="255" step="1" id="blue" value="162">
<div id="display" style="height: 50px; width: 50px;"></div>
</div>
<script type="text/javascript">
var input = document.querySelectorAll("input");
for (var i = 0; i < input.length; i++) {
input[i].addEventListener("input",
function () {
var
red = document.getElementById("red").value,
green = document.getElementById("green").value,
blue = document.getElementById("blue").value;
var display = document.getElementById("display");
display.style.background = "rgb(" + red + ", " + green + ", " + blue + ")";
}
);
}
</script>
</body>

How to get the value of a range slider?

Can you please help me how to get values of a range slider in javascript?
<script>
$(function()
{
$('.slider').on('input change', function(){
$(this).next($('.slider_label')).html(this.value);
});
$('.slider_label').each(function(){
var value = $(this).prev().attr('value');
$(this).html(value);
});
})
</script>
<p><label for="range_size">Size: </label> <input type="range" name="size" class="slider" min="1" max="75" value="45">
<span class="slider_label"></span></p>
<p><label for="range_width">Width: </label> <input type="range" name="width" class="slider" min="1" max="6" value="1">
<span class="slider_label"></span></p>
I am trying to get like this :
<script type="text/javascript">
function calculate () {
var size = document.getElementById ("size").value;
alert(size);
</script>
But it doesn't show any alert. Can you please help me?
Using value does work :
let p = document.getElementById("val")
let range = document.getElementById("slide")
let changeVal = () => {
p.textContent = range.value
}
changeVal()
range.onchange = changeVal
<input id="slide" type="range" min="0" max="100"/><p id="val"></p>
as B001ᛦ said in comment the problem is you forgot to add an id on your <input>
If you prefer you can also use names but you need to take care as name can be reused while Ids are unique
let p = document.getElementsByName("val")[0]
let range = document.getElementsByName("slide")[0]
let changeVal = () => {
p.textContent = range.value
}
changeVal()
range.onchange = changeVal
<input name="slide" type="range" min="0" max="100"/><p name="val"></p>
getElementsByName return a NodeList so you'll need to get the node you need from this list (the first one if you have only one)
as a side note value does exists on every input type

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>

Categories

Resources