Reputation: 495
I have an HTML number input and follows a selection for unit types.
<input type="number" id="foo" min = "1" max = "10" value = "2" onblur = "if(Number(this.value)<Number(this.min))this.value=this.min; if(Number(this.value)>Number(this.max))this.value=this.max;">
<select id="foo-unit">
<option value="1000">m</option>
<option value="1">mm</option>
<option value="25.4">inches</option>
</select>
The unit types options are meter (m) and millimeter (mm) for example.
There are limits for the number input, min is 1 meter and max is 10 meters. So if the unit is changed to mm, the min is 1000 mm and the max is 10000 mm.
There are two questions:
Thanks,
Upvotes: 1
Views: 952
Reputation: 1387
var foo = document.getElementById("foo")
function changeVal(self){
if(Number(self.value)<Number(self.min))self.value=self.min; if(Number(self.value)>Number(self.max))self.value=self.max;
}
function changeUnit(unitStep){
foo.value = foo.value * unitStep;
foo.min = foo.min * unitStep;
foo.max = foo.max * unitStep;
}
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<input type="number" id="foo" min = "1" max = "10" value = "2" onblur = "changeVal(this)">
<select id="foo-unit" onchange="changeUnit(this.options[this.options.selectedIndex].value)">
<option value="0.001">m</option>
<option value="1000">mm</option>
</select>
</body>
</html>
Upvotes: 1
Reputation: 563
Try below code, you can add option to select for new unit.
function changeUnit(){
var input = document.getElementById("input");
var unitSelect = document.getElementById("unitSelect");
var currentConvert = Number.parseFloat(document.querySelector("option[value="+input.getAttribute("unit")+"]").getAttribute("convert"));
var newUnit = document.querySelector("option[value="+ unitSelect.value +"]");
var newConvert = Number.parseFloat(newUnit.getAttribute("convert"));
var currentValue = Number.parseFloat(input.value);
// Convert to new unit
var newValue = currentValue*(currentConvert/newConvert);
// Set new value, unit, min and max to input
input.value = Number.parseFloat(newValue);
input.setAttribute('unit', newUnit.value);
input.setAttribute('min', newUnit.getAttribute('min'));
input.setAttribute('max', newUnit.getAttribute('max'));
}
<input id='input' type='number' min=0 value='1' max='10' unit='m' style='text-align: right; width: 70px;'/>
<select id="unitSelect" onchange="changeUnit()">
<option selected value='m' min='1' max='10' convert='1000'>m</option>
<option value='cm' min='100' max='1000' convert='10'>cm</option>
<option value='mm' min='1000' max='10000' convert='1'>mm</option>
<option value="inches" min = 10 max='100' convert='25.4'>inches</option>
</select>
Upvotes: 1
Reputation: 5237
It seems you are close, but you need to react to the select
option being changed rather than the input
field being changed.
When the select
option is changed, you just need to set the min/max according to the selected option -- and, then just convert the unit as needed.
I've also moved this logic into a function called update
, rather than trying to fit it inline -- which is really hard to read and debug if its more than a simple statement or two.
Consider this working snippet:
function update(elem) {
const input = document.getElementById('foo');
if (elem.value === '1000') {
input.setAttribute('min', '1');
input.setAttribute('max', '10');
input.value /= 1000;
} else {
input.setAttribute('min', '1000');
input.setAttribute('max', '10000');
input.value *= 1000;
}
}
<input type="number" id="foo" min="1" max="10" value="2">
<select id="foo-unit" onchange="update(this)">
<option value="1000">m</option>
<option value="1">mm</option>
</select>
Edit:
If there are more units involved, then you can generalize the above easily. You just need to keep track of the previous unit so you can do the conversion correctly when the unit is changed. That's what the previous
variable does here - it updates every time the selected option is changed. The rest follows in the same way, except there is an extra case (for inches).
// initial unit is m (1000 mm)
let previous = '1000';
const min = 1000; // in mm
const max = 10000; // in mm
function update(elem) {
// get value of input field in the current unit
const input = document.getElementById('foo');
// update the min/max according to the selected unit
input.setAttribute('min', Math.floor(min / elem.value));
input.setAttribute('max', Math.floor(max / elem.value));
// convert value in input field to new unit
input.value = input.value * previous / elem.value;
// save unit for subsequent conversion
previous = elem.value;
}
<input type="number" id="foo" min="1" max="10" value="2">
<select id="foo-unit" onchange="update(this)">
<option value="1000">m</option>
<option value="1">mm</option>
<option value="25.4">inches</option>
</select>
Upvotes: 2
Reputation: 106
const option = document.getElementById('foo-unit');
const inputEl = document.getElementById('foo');
option.addEventListener('change', function() {
if(option.value === 'mm') {
var inputValue = inputEl.value;
inputEl.value = inputValue * 1000;
inputEl.setAttribute('min', '1000');
inputEl.setAttribute('max', '10000');
} else {
var inputValue = inputEl.value;
inputEl.value = inputValue / 1000;
inputEl.setAttribute('min', '1');
inputEl.setAttribute('max', '10');
}
})
<input type="number" id="foo" min = "1" max = "10" value = "2">
<select id="foo-unit">
<option value="m">m</option>
<option value="mm">mm</option>
</select>
This is a simple solution using JS, but this code can be optimized, it's just written explicitly to give you an idea. While entering the number directly in the input box, it can take values beyond limits but when you submit the form, an error will be shown. That can be modified by adding some more code to show the error instantly.
Upvotes: 1
Reputation:
Just add an onchange event in the <select>
tag:
function changeUnit() {
var x = document.getElementById("foo-unit").value;
if (x === "1") {
document.getElementById("foo").max = 10000;
document.getElementById("foo").min = 1000;
}
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<input type="number" id="foo" value = "2" min="1" max="10" onblur="if(Number(this.value)<Number(this.min))this.value=this.min; if(Number(this.value)>Number(this.max))this.value=this.max;">
<select id="foo-unit" onchange="changeUnit()">
<option value="1000">m</option>
<option value="1">mm</option>
</select>
</body>
</html>
Upvotes: 1