SelectionStart/selectionEnd по типу ввода = "номер" больше не разрешен в Chrome

Наше приложение использует selectStart в полях ввода, чтобы определить, следует ли автоматически перемещать пользователя в следующее/предыдущее поле, когда они нажимают клавиши со стрелками (т.е. когда выделение находится в конце текста, и пользователь нажимает стрелку вправо мы переходим к следующему полю, в противном случае)

Chrome теперь запрещает использование функции selectStart, где type = "number". Теперь это исключает исключение:

Failed to read the 'selectionStart' property from 'HTMLInputElement': The input element type ('number') does not support selection.

Смотрите следующее:

https://codereview.chromium.org/100433008/#ps60001

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#do-not-apply

Можно ли определить местоположение каретки в поле ввода типа = "число"?

Ответ 1

Выбор разрешен только с текстом/поиском, URL-адресом, телом и паролем. Вероятная причина, по которой выбор был отключен для ввода номера типа, заключается в том, что на некоторых устройствах или при некоторых обстоятельствах (например, когда ввод был представлен как короткий list), может не быть каретки. Единственное решение, которое я нашел, это изменить тип ввода на текст (с соответствующим шаблоном для ограничения ввода). Я все еще ищу способ сделать это без изменения типа ввода и опубликую обновление, когда найду что-то.

Ответ 2

Я нашел простой обходной путь (проверенный на Chrome) для setSelectionRange(). Вы можете просто изменить type на text, прежде чем использовать setSelectionRange(), а затем изменить его на number.

Вот простой пример с jquery, который будет позиционировать каретку в позиции 4 на вводе номера всякий раз, когда вы нажимаете на вход (добавьте более 5 цифр на вкладке, чтобы увидеть поведение)

plunker

Ответ 3

В настоящее время единственными элементами, которые позволяют безопасно выбирать текст, являются:

<input type="text|search|password|tel|url">, как описано в:
атрибут whatwg: selectionStart.

Вы также можете прочитать документацию по интерфейсу HTMLInputElement, чтобы ближе рассмотреть элементы ввода.

Чтобы безопасно преодолеть эту "проблему", лучше всего разобраться с <input type="text"> и применить маску/ограничение, которые принимают только числа. Есть несколько плагинов, которые удовлетворяют требованию:

Вы можете увидеть живую демонстрацию одного из предыдущих плагинов здесь:

Если вы хотите безопасно использовать selectionStart, то вы можете проверить те элементы, которые его поддерживают (см. атрибуты типа ввода)

Реализация
// Fix: failed to read the 'selectionStart' property from 'HTMLInputElement'
// The @fn parameter provides a callback to execute additional code
var _fixSelection = (function() {
    var _SELECTABLE_TYPES = /text|password|search|tel|url/;
    return function fixSelection (dom, fn) {
        var validType = _SELECTABLE_TYPES.test(dom.type),
            selection = {
                start: validType ? dom.selectionStart : 0,
                end: validType ? dom.selectionEnd : 0
            };
        if (validType && fn instanceof Function) fn(dom);
        return selection;
    };
}());

// Gets the current position of the cursor in the @dom element
function getCaretPosition (dom) {
    var selection, sel;
    if ('selectionStart' in dom) {
        return _fixSelection(dom).start;
    } else { // IE below version 9
        selection = document.selection;
        if (selection) {
            sel = selection.createRange();
            sel.moveStart('character', -dom.value.length);
            return sel.text.length;
        }
    }
    return -1;
}

Usage

Usage
// If the DOM element does not support 'selectionStart',
// the returned object sets its properties to -1.
var box = document.getElementById("price"),
    pos = getCaretPosition(box);
console.log("position: ", pos);

Приведенный выше пример можно найти здесь: jsu.fnGetCaretPosition()

Ответ 5

В качестве рабочего порядка входной тип type="tel" обеспечивает очень схожую функциональность с type="number" в Chrome и не имеет этого ограничения (как указал Патрис).

Ответ 6

Есть один способ, которым вы можете выполнить это в Chrome (и, возможно, в некоторых других браузерах, но Chrome - большой преступник). Используйте window.getSelection() для извлечения объекта выделения из текущего ввода, а затем тест продлить выбор назад (или вперед) и посмотреть, изменится ли значение toString() выбора. Если это не так, курсор находится в конце ввода, и вы можете перейти к следующему входу. Если это так, вы должны затем отменить операцию, чтобы отменить выбор.

s = window.getSelection();
len = s.toString().length;
s.modify('extend', 'backward', 'character');
if (len < s.toString().length) {
    // It not at the beginning of the input, restore previous selection
    s.modify('extend', 'forward', 'character');
} else {
    // It at the end, you can move to the previous input
}

Я получил эту идею из этого SO-ответа: fooobar.com/questions/25687/...

Ответ 7

мы не можем просто отменить проверку элемента, чтобы просто включить поддерживаемые элементы, например:

if (deviceIsIOS &&
    targetElement.setSelectionRange &&
    (
        targetElement.type === 'text' ||
        targetElement.type === 'search' ||
        targetElement.type === 'password' ||
        targetElement.type === 'url' ||
        targetElement.type === 'tel'
    )
) {

вместо этого:

if (deviceIsIOS && 
    targetElement.setSelectionRange && 
    targetElement.type.indexOf('date') !== 0 && 
    targetElement.type !== 'time' && 
    targetElement.type !== 'month'
) {

Ответ 8

Хотя проблема с устаревшими событиями для этого типа поля формы может быть актуальной, насколько я вижу, этот вид поля можно прослушать с событием "изменение", как обычно.

Я попал в эту статью здесь, ища ответ на вопрос о событиях для этого типа поля, но, проверяя его, я обнаружил, что могу просто полагаться на событие "change", как упоминалось.

Ответ 9

Я получил эту ошибку на веб-сайте angularjs.

Я создал атрибут пользовательских данных на входе и также использовал ng-blur (с $event).

Когда мой callback был вызван, я пытался получить доступ к значению "data-id", например:

var id = $event.target.attributes["data-id"]

И это должно быть так:

var id = $event.target.attributes["data-id"].value

Кажется, что в этой ошибке нет слишком многого, поэтому я оставляю это здесь.

Ответ 10

Я знаю, что этот ответ приходит слишком поздно, но вот плагин, который реализует selectionStart для всех типов элементов, для большинства браузеров (старых и новых):

https://github.com/adelriosantiago/caret

Я обновил его, чтобы решить проблему type="number" с помощью ответа @ncohen.

Ответ 11

Решите Failed to read the 'selectionStart' property from 'HTMLInputElement': The input element type ('number') does not support selection. следующим образом:

var checkFocus = false;
var originalValue = "";
$(document).ready(function() {
  $("input").focus(function() {
    var that = this;
    if ($('#' + $(this).context.id).attr("type") == "text") {
      setTimeout(function() {
        if (that.selectionStart != null || that.selectionEnd != null) {
          that.selectionStart = that.selectionEnd = 10000;
        }
      }, 0);
    } else if ($('#' + $(this).context.id).attr("type") == "number") {
      if (checkFocus) {
        moveCursorToEnd($('#' + $(this).context.id), $(this).context.id);
        checkValue($('#' + $(this).context.id))
        checkFocus = false;
      } else {
        $('#' + $(this).context.id).blur();
      }
    }
  });
});

function FocusTextBox(id) {
  checkFocus = true;
  document.getElementById(id).focus();
}

function checkValue(input) {
  if ($(input).val() == originalValue || $(input).val() == "") {
    $(input).val(originalValue)
  }
}

function moveCursorToEnd(input, id) {
  originalValue = input.val();
  input.val('');
  document.getElementById(id).focus();
  return originalValue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<button onclick="FocusTextBox('textid')">
   <input id="textid" type="number" value="1234" > 
</button>

Ответ 12

Следите за ошибочными результатами в Angular, если используете режим тестирования устройств Chrome.

Так что это явно Chrome, а не реальный iPhone - но ошибка все равно возникает, потому что _platform.IOS возвращает true, а затем setSelectionRange впоследствии терпит неудачу.

Это Angular - но подобные проблемы могут существовать в других средах/средах.

enter image description here