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()
Ответ 4
Это происходило для нас при использовании JQuery Numeric Plugin версии 1.3.x, поэтому, обернув selectionStart
и selectionEnd
с помощью try...catch{}
, мы смогли подавить ошибку.
Источник: https://github.com/joaquingatica/jQuery-Plugins/commit/a53f82044759d29ff30bac698b09e3202b456545
Ответ 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]()