selectionStart / selectionEnd no tipo de input = “number” não é mais permitido no Chrome

Nosso aplicativo usa selectionStart nos campos de input para determinar se deve mover automaticamente o usuário para o campo próximo / anterior quando eles pressionam as teclas de seta (ou seja, quando a seleção está no final do texto e o usuário pressiona a seta para a direita o próximo campo, caso contrário)

O Chrome agora impede que o selectionStart seja usado em type = “number”. Agora lança a exceção:

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

Veja a seguir:

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

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

Existe alguma maneira de determinar a localização do cursor em um campo de input do tipo = “número”?

A seleção só é permitida com texto / pesquisa, URL, tel e senha . O motivo provável de a seleção ter sido desativada para inputs do tipo number é que, em alguns dispositivos, ou em algumas circunstâncias (por exemplo, quando a input foi apresentada, é apresentada como uma list resumida), pode não haver um sinal de intercalação. A única solução que encontrei foi alterar o tipo de input para texto (com padrão apropriado para restringir a input). Ainda estou procurando uma maneira de fazer isso sem alterar o tipo de input e postarei uma atualização quando encontrar algo.

Atualmente, os únicos elementos que permitem a seleção de texto com segurança são:

como descrito em:
atributo whatwg: selectionStart .

Você também pode ler a documentação da interface HTMLInputElement para observar mais de perto os elementos de input.

Para superar esse “problema” com segurança, o melhor por agora é lidar com um e aplicar uma máscara / restrição que aceite apenas números. Existem alguns plugins que satisfazem o requisito:

Você pode ver uma demonstração ao vivo de um dos plugins anteriores aqui:

Se você quiser usar com segurança selectionStart , então você pode verificar os elementos que o suportam (veja os atributos do tipo de input )

Implementação

 // 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; } 

Uso

 // 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); 

O exemplo acima pode ser encontrado aqui: jsu.fnGetCaretPosition ()

Eu encontrei uma solução simples (testado no Chrome) para setSelectionRange() . Você pode simplesmente alterar o type para text antes de usar setSelectionRange() e, em seguida, alterá-lo novamente para o number .

Aqui está um exemplo simples com jquery que posicionará o cursor na posição 4 na input do número sempre que você clicar na input (adicione mais de 5 números na input para ver o comportamento)

plunker

Isso estava acontecendo para nós enquanto usavamos o jQuery Numeric Plugin, versão 1.3.x, então encapsulando selectionStart e selectionEnd com um try...catch{} nós conseguimos suprimir o erro.

Fonte: https://github.com/joaquingatica/jQuery-Plugins/commit/a53f82044759d29ff30bac698b09e3202b456545

Como solução alternativa, o type="tel" input type="tel" fornece funcionalidade muito semelhante ao type="number" no Chrome e não tem essa limitação (como apontado por Patrice).

Existe uma maneira de fazer isso no Chrome (e talvez em alguns outros navegadores, mas o Chrome é o grande ofensor aqui). Use window.getSelection() para recuperar o object de seleção da input atual e, em seguida, estenda a seleção para trás (ou encaminha) e veja se o valor toString() da seleção é alterado. Se isso não acontecer, o cursor estará no final da input e você poderá passar para a próxima input. Em caso afirmativo, você deve inverter a operação para desfazer a seleção.

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

Eu tenho essa idéia desta resposta SO: https://stackoverflow.com/a/24247942

Não podemos apenas inverter a verificação de elemento para include apenas os elementos que são suportados, como este:

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

em vez disso:

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

Embora o problema com os events reprovados para esse tipo de campo de formulário ainda possa ser relevante, até onde eu possa ver, esse tipo de campo pode ser ouvido com o evento “change”, como de costume.

Cheguei a este artigo aqui enquanto procurava por uma resposta ao problema de events para esse tipo de campo, mas, ao testá-lo, descobri que posso simplesmente confiar no evento “change”, conforme mencionado.

Recebi este erro em um site angularjs.

Eu tinha criado um atributo de dados personalizado em uma input e também estava usando ng-blur (com $ event).

Quando meu callback foi chamado, eu estava tentando acessar o valor ‘data-id’ como:

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

E deveria ter sido assim:

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

Não parece haver muito sobre este erro em qualquer lugar, por isso estou deixando isso aqui.

Eu sei que esta resposta vem tarde demais, mas aqui está um plug-in que implementa selectionStart para todos os tipos de elementos, para a maioria dos navegadores (antigo e novo):

https://github.com/adelriosantiago/caret

Eu atualizei para lidar com o problema type="number" usando a resposta de @ncohen.