HTML input field with automatically retrieving the granularity from minutes, hours and days

Viewed 138

I need to have an input field to set the duration.

The user will have the possibility to set this duration in minutes, hours or days

For example, I would like to give the possibility to have inputs like:

1m
8.5 h
3d

etc

I will convert the value to minutes before to send the value to the backend.

Do you know some inputs plugins to have this?

4 Answers

Using moment.js you can allow inputs as follows:

const threeMinuts = '3m';       // 3 minutes
const eightHours  = '8.5 h';    // 8.5 hours
const threeDays   = '3 days';      // 3 days

You then have to separate the number value from the unit of measurement:

const numberValue = Number(input.match(/(\d|\.|,)+/)[0]);
const unit = input.match(/[a-z]+/)[0];

after which you can pass the duration to moment as follows:

const duration = moment.duration(numberValue, unit);

e.g.:

const duration = moment.duration(8.5, 'h');
  1. Assign each <input> type="number" and min="0".

  2. Then max="23" for hours and max="59" for minutes.

  3. Add a hidden input with a name attribute.

  4. If you haven't already, wrap everything in a <form> and register it to the "input" event.

  5. Create an event handler to extract and calculate the values of all of the inputs and then assign the total to the hidden input.

  6. When the <form> is submitted, the hidden input value will be sent since it has a name attribute.

BTW it isn't really good UX to have a user type in so many values in one input. You should provide the user clearly defined fields that require the user to enter data without extra complications.


Demo

document.forms.duration.oninput = toMinutes;

function toMinutes(e) {
  const dur = this.elements;
  let time;
  if (e.target.tagName === 'INPUT') {
    let d = Number(dur.days.value) * 1440;
    let h = Number(dur.hours.value) * 60;
    let m = Number(dur.minutes.value);
    time = d + h + m;
    dur.time.value = time;
  }
  console.log(dur.time.value);
}
:root,
body {
  font: 400 3vw/1.45 Consolas
}

fieldset {
  width: max-content;
}

label,
input {
  width: 6.5ch;
  display: inline-block;
  margin: 4px;
}

input {
  height: 3vw;
  line-height: 1;
  font: inherit;
  text-align: right
}

.as-console-wrapper {
  width: 40%;
  min-height: 100%;
  margin-left: 60%;
}
  
<form id='duration'>
  <fieldset>
    <legend>Duration</legend>
    <label for='days'>Days: </label>
    <input id='days' type='number' min='0' value='0'><br>
    <label for='hours'>Hours: </label>
    <input id='hours' type='number' min='0' max='23' value='0'><br>
    <label for='minutes'>Minutes: </label>
    <input id='minutes' type='number' min='0' max='59' value='0'><br>
  </fieldset>
  <input id='time' name='time' type='hidden'>
</form>

As I prefer pure JS and no libs (with a heavy overhead) here a simple JS for this task adapt (esp the regex eg for hours (/([0-9]0-9?)[ ]?h/) for digits) as you like:

function toSeconds(dd,hh,mm) {
 var d = parseInt(dd);
  var h = parseInt(hh);
  var m = parseInt(mm);
  if (isNaN(d)) d = 0;
  if (isNaN(h)) h = 0;
  if (isNaN(m)) m = 0;

 var t = d * 24 * 60 * 60 +
      h * 60 * 60 +
      m * 60;
  return t;
}

/* Expects 1d 11h 11m, or 1d 11h, or 11h 11m, 
or 11h, or 11m, or 1d returns number of seconds */
function parseInput(sInput) {
  if (sInput== null || sInput=== '') return 0;
  var mrx = new RegExp(/([0-9][0-9]?)[ ]?m/);
  var hrx = new RegExp(/([0-9][0-9]?)[ ]?h/);
  var drx = new RegExp(/([0-9])[ ]?d/);
  var days = 0;
  var hours = 0;
  var minutes = 0;
  if (mrx.test(sInput)) {
    minutes = mrx.exec(sInput)[1];
  }
  if (hrx.test(sInput)) {
    hours = hrx.exec(sInput)[1];
  }
  if (drx.test(sInput)) {
    days = drx.exec(sInput)[1];
  }

  return toSeconds(days, hours, minutes);
}

First, you create input

<input id="time" type="time">

Finally, you add value into input using javascript

document.getElementById("time").value = new Date().toTimeString().slice(0,8);
Related