Home > OS >  How to make a text-type input-element accept just a numerical value (decimal, positive and negative)
How to make a text-type input-element accept just a numerical value (decimal, positive and negative)

Time:10-06

I have an HTML input and this input just accept the string of number character,

Example:

input value: 0123.534534 or -234234.543345 or -13453, these input values are valid. The characters or - just exist one and at first position in string value

I want every typing character the input value should keep the current valid string and replace the invalid input character with an empty character

Example:

When I typed : 123.g ==> the value should replace immediately 123. Or when I typed: g ==> the value should replace immediately with an empty value.

I found an implementation with this, but It lack of ( /-/.) character

const getDigitsOnly = (value) => String(value).replace(NOT_NUMBERS, '');

CodePudding user response:

From the above comments ...

"Why does the OP not restrict the user input by a number type input field like with ... <input type="number"/>?"

"Any type="text" and custom validation based approach, if done properly, has the tendency to grow more complex since, from a UX perspective, an immediate value sanitizing (while typing or pasting) also has to take care of reestablishing the user's most recent caret position."

Proving the above mentioned complexity ...

function stripNeedlessDataFromBoundFieldValue() {
  this.value = this.value.replace((/[- .]$/), '');
}

function getSanitizedValue(value) {
  value = value
    // remove any leading and trailng whitespace (sequences).
    .trim()
    // remove any character not equal to minus, plus, dot and digit.
    .replace((/[^- .\d] /g), '');

  if (value.length >= 1) {

    let partials = value.split(/(^[ -]?)/);
    if (partials.length === 1) {

      partials.unshift('');
    } else {
      partials = partials.slice(1);
    }
    let [ first, last ] = partials;

    last = last.replace((/[ -] /g), '');

    // console.log([ first, last ]);

    partials = last.split('.');
    if (partials.length === 1) {

      partials.unshift('');
    } else {
      partials = [
        partials.shift(),
        ['.', partials.join('')].join(''),
      ];
    }
    first = [first, partials[0]].join('');
    last = partials[1];

    value = [first, last]
      .join('')
      .replace(
        // trim any sequence of leading zeros into a single one.
        (/(^[ -]?)0 /),
        (match, sign) => [(sign || ''), 0].join('')
      )
      .replace(
        // always ensure a single zero before a leading sole decimal point.
        (/(^[ -]?)\. /),
        (match, sign) => [(sign || ''), '0.'].join('')
      );
  }
  return value;
}

function sanitizeInputValue(evt) {
  const elmNode = evt.currentTarget;

  const currentValue = elmNode.value;
  const sanitizedValue = getSanitizedValue(currentValue);

  if (currentValue !== sanitizedValue) {
    const diff = sanitizedValue.length - currentValue.length;
    const { selectionStart, selectionEnd } = elmNode;

    elmNode.value = sanitizedValue;

    elmNode.selectionStart =
      (selectionStart   diff > 0) ? selectionStart   diff : selectionStart;
    elmNode.selectionEnd =
      (selectionEnd   diff > 0) ? selectionEnd   diff : selectionEnd;
  }
}

function main() {
  const textInput = document.querySelector('[type="text"]');

  const finalizeBoundFieldValueDebounced = _.debounce(
    stripNeedlessDataFromBoundFieldValue.bind(textInput), 1200
  );
  textInput.addEventListener('input', evt => {
    sanitizeInputValue(evt);
    finalizeBoundFieldValueDebounced();
  });

  // // whithout delayed trimming of trailing dot.
  //
  // document
  //   .querySelector('[type="text"]')
  //   .addEventListener('input', sanitizeInputValue);
}

main();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script>

<input type="text" placeholder="... number only ..."/>

... and comparing it directly to the number type field ...

<input type="number" placeholder="native number type"/>

... and to Micahel Hamami's approach, which hereby got brought into action ...

function sanitizeInputValue({ currentTarget }) {
  currentTarget.value = currentTarget.value.replace(/[^0-9, ,-,.] /g, "");
}
function main() {
  document
    .querySelector('[type="text"]')
    .addEventListener('input', sanitizeInputValue);
}
main();
<input type="text" placeholder="... number only ..."/>

CodePudding user response:

Here is my solution for it.

We add an input event listener to the input box and for every input we format the entire input value.

Note: Don't forget to trim trailing decimal point (e.g. "123." to "123") if exists when submitting the value.

const inputBox = document.getElementById("inputBox");

inputBox.addEventListener("input", () => {
  inputBox.value = format(inputBox.value);
});

function format(str) {
  if (!str.length) return str;

  str = str.replace(/[^. -\d]/g, "");
  const firstChar = str.charAt(0);
  str = str.slice(1).replace(/[ -]/g, "");

  // Bug fix. Credit goes to @Peter Seliger
  // For pointing out the bug
  const charArray = [];
  let hasDecimalPoint = false;

  if (firstChar === ".") {
    if (!str.includes(".")) {
      hasDecimalPoint = true;
      charArray.push("0.");
    }
  } else charArray.push(firstChar);
  // End bug fix

  for (let i = 0; i < str.length; i  ) {
    const char = str.charAt(i);

    if (char === ".") {
      if (hasDecimalPoint) continue;
      if (!i && firstChar !== "0") charArray.push("0");
      hasDecimalPoint = true;
    }

    charArray.push(char);
  }

  return charArray.join("");
}
<p>Enter your number here</p>
<input id="inputBox" type="text" />

The algorithm of the format function.

1: If the input is empty then return the input
2: Remove all characters except "-", " ", "." and digits
3: Store the first character in a variable
4: Remove all " " and "-" (if exists) after the first character
5: if the first character is "." then replace it with "0."
6. Finally remove any duplicate decimal point (".") if exists

And here are some dummy data to test the format function

const dummyData = [
  "",
  " ",
  "-",
  ".",
  ".123",
  " .123",
  "123.3.23",
  "12sfdlj3lfs.s  d_f",
  "12--  .123",
];

CodePudding user response:

this will do what you want

    let someString = " 123.g";
    let result = someString.replace(/[^0-9, ,-,.] /g, "");
    console.log(result);

for more info on how to use regex check here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

  • Related