Xuhang
Xuhang

Reputation: 495

html number input box change according to the following unit labels

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:

  1. If I switch the unit, how can I change the input box's max/min limit accordingly?
  2. If there is an input value in the box already, say 1 m. I switch to the unit of mm (or inches), how to change the values of the input box to 1000 mm (or 39.37 inches) accordingly?

Thanks,

Upvotes: 1

Views: 952

Answers (5)

Para
Para

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

Manh Nguyen
Manh Nguyen

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

costaparas
costaparas

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

hashBender
hashBender

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

user14697373
user14697373

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

Related Questions