Как предотвратить перемещение курсора при изменении значения ввода? - PullRequest
0 голосов
/ 30 октября 2019

Я создаю числовую пару маска ввода / значение, показывая пользователю ввод текста, чтобы дать ему несколько стилей (т.е. деление тысяч через запятую), и сохраняю реальное значение для отправки в форму в скрытом числе. input.

Прямо сейчас я замечаю, что редактирование значения видимого ввода обновляет индекс выбора до самого конца, что не интуитивно понятно при редактировании ввода, например, середина значения . Я понимаю, что позиция была потеряна, так как значение полностью переписано, но как я могу вручную отследить его, чтобы обновить его обратно, учитывая, что обработчик события on.('input') запускает "после", значение уже изменилось, а keydown событие происходит до модификации?

$("#foo").on('change paste input mouseup', function() {
  const validation_decimals = 3 //allowed decimal places
  const $mask = $('#foo')
  const $value = $('#baz')
  let hasDot = $mask.val().includes('.')
  let nValue = $mask.val().replace(/[a-zA-Z]/g, "").replace(/[!¡@#$%^&\/+*()=¿?":;\[\]\-_~`\\{}'|<>]/g, "")

  // only one period allowed
  if (hasDot) {
    if ($mask.val().match(/\./g).length > 1) {
      let newVal = $mask.val()
      const lastDot = newVal.lastIndexOf('.')
      newVal = newVal.slice(0, lastDot) + newVal.slice(lastDot + 1)
      $mask.val(newVal)
    }
  }
  $value.val(parseFloat($mask.val().replace(/,/g, "")))

  // adding comma-based thousands grouping
  let [integers, decimals] = $value.val().toString().split('.')
  if (integers.length > 3) {
    for (let iReverse = -3; iReverse > -integers.length; iReverse -= 4) {
      integers = integers.slice(0, iReverse) + ',' + integers.slice(iReverse)
    }
  }

  let fValue = integers

  if (hasDot) {
    fValue += '.'
  }

  if (decimals !== undefined) {
    fValue += decimals
  }

  $('#foo').val(fValue)
})

// preventing more decimal places than allowed and user-inputted commas.
$("#foo").on('select click keydown', function(e) {
  let selStart = e.target.selectionStart;
  let selEnd = e.target.selectionEnd;
  const isComma = e.keyCode == 188
  const isNumber = (e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105)
  const validation_decimals = 3
  if ($(this).val().includes('.')) {
    const value = $(this).val()
    const decimals = value.split('.')[value.split('.').length - 1]
    const decimalLengthReached = decimals.length == validation_decimals
    const selectionBeforePeriod = selStart < value.indexOf('.') || selEnd > selStart
    if (isNumber && decimalLengthReached && !selectionBeforePeriod) {
      e.preventDefault()
    }
  }
  if (isComma) {
    e.preventDefault()
  }
})
.input-group {
  margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='form-group'>
  <label for='foo'>User Field (type here)</label>
  <div class="input-group mb-3">
    <input type="text" class="form-control" id='foo' step='0.01' aria-label="Amount (to the nearest dollar)">
  </div>
  <label for='baz'><em>Hidden field</em></label>
  <div class="input-group mb-3">
    <input type="number" id='baz' aria-label="Amount (to the nearest dollar)" step='0.1'>
  </div>
</div>

1 Ответ

1 голос
/ 30 октября 2019

Вы можете использовать свойство selectionStart полей ввода, чтобы определить, где находится курсор, прежде чем полностью переписать поле ввода.

document.querySelector("#my-input").addEventListener("change", function() {
  // Get the position of the caret before you rewrite the input field
  let caretPosition = document.querySelector("#my-input").selectionStart;

  // Rewrite the input field here

  // Put the caret back to where it was
  document.querySelector("#my-input").selectionStart = caretPosition;
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...