web-dev-qa-db-fra.com

selectionStart / selectionEnd sur le type d'entrée = "numéro" n'est plus autorisé dans Chrome

Notre application utilise selectionStart sur les champs de saisie pour déterminer s'il convient de déplacer automatiquement l'utilisateur vers le champ suivant/précédent lorsqu'il appuie sur les touches fléchées (c'est-à-dire, lorsque la sélection est à la fin du texte et que l'utilisateur appuie sur la flèche vers la le champ suivant, sinon)

Chrome empêche désormais l’utilisation de selectionStart où type = "nombre". Il jette maintenant l'exception:

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

Voir ci-dessous:

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

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

Existe-t-il un moyen de déterminer l'emplacement du curseur dans un champ de saisie de type = "numéro"?

71
Steven

La sélection n'est autorisée qu'avec text/search, URL, tel et mot de passe . La raison probable pour laquelle la sélection a été désactivée pour les entrées de numéro de type est que, sur certains périphériques ou dans certaines circonstances (par exemple, lorsque l'entrée a été présentée sous la forme d'un court list), il pourrait ne pas y avoir de curseur. . La seule solution que j'ai trouvée consistait à modifier le type de saisie en texte (avec le modèle approprié pour limiter les saisies). Je cherche toujours un moyen de faire avec sans changer le type d'entrée et posterai une mise à jour lorsque je trouverai quelque chose.

38
Patrice Chalin

J'ai trouvé une solution de contournement simple (testée sur Chrome) pour setSelectionRange(). Vous pouvez simplement changer le type en text avant d'utiliser setSelectionRange(), puis le remettre à number.

Voici un exemple simple avec jquery qui positionnera le curseur à la position 4 dans l'entrée du numéro lorsque vous cliquez dessus (ajoutez plus de 5 chiffres dans l'entrée pour voir le comportement)

plunker

16
ncohen

Actuellement, les seuls éléments permettant une sélection de texte en toute sécurité sont:

<input type="text|search|password|tel|url"> comme décrit dans:
whatwg: attribut selectionStart.

Vous pouvez également lire la documentation de interface HTMLInputElement pour examiner de plus près les éléments en entrée.

Pour surmonter ce "problème" en toute sécurité, le mieux pour le moment est de traiter avec un <input type="text"> et appliquez un masque/une contrainte qui accepte uniquement des nombres. Il existe des plugins qui satisfont à l'exigence:

Vous pouvez voir une démonstration en direct de l'un des plugins précédents ici:

Si vous voulez utiliser en toute sécurité selectionStart, vous pouvez alors rechercher les éléments qui le prennent en charge (voir attributs de type d'entrée )

La mise en oeuvre

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

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

L'exemple ci-dessus peut être trouvé ici: jsu.fnGetCaretPosition ()

14
jherax

Vous pouvez y parvenir de la même manière sur Chrome (et peut-être quelques autres navigateurs, mais Chrome est le grand contrevenant ici)). Utilisez window.getSelection() pour récupérer l’objet de sélection à partir de l’entrée actuelle, puis tester pour étendre la sélection en arrière et voir si la valeur de la sélection toString() change. Si ce n’est pas le cas, le curseur se fin de la saisie et vous pouvez passer à la saisie suivante, sinon vous devez inverser l’opération pour annuler la sélection.

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
}

J'ai eu cette idée de cette SO réponse: https://stackoverflow.com/a/24247942

5
Pre101

Cela se produisait pour nous lorsque nous utilisions le plugin jQuery Numeric, version 1.3.x, si bien envelopper les selectionStart et selectionEnd avec un try...catch{} nous avons pu supprimer l’erreur.

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

5
jbwebtech

Pour contourner le problème, le type="tel" Le type d’entrée fournit des fonctionnalités très similaires à type="number" in Chrome et n’a pas cette limitation (comme le souligne Patrice).

5
Kevin Borders

ne pouvons-nous pas simplement inverser la vérification des éléments pour inclure uniquement les éléments pris en charge, comme ceci:

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

au lieu de cela:

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

J'ai reçu cette erreur sur un site Web angularjs.

J'avais créé un attribut de données personnalisé sur une entrée et utilisais également ng-blur (avec $ event).

Lorsque mon rappel a été appelé, j'essayais d'accéder à la valeur 'data-id' comme suit:

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

Et ça aurait dû être comme ça:

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

Il ne semble pas y avoir trop d’informations sur cette erreur, je la laisse donc ici.

1
Mike Cheel

Bien que le problème des événements déconseillés pour ce type de champ de formulaire puisse être toujours d'actualité, autant que je sache, ce type de champ peut être écouté avec l'événement "change", comme d'habitude.

Je suis arrivé à cet article ici en cherchant une réponse au problème des événements pour ce type de champ, mais en le testant, j'ai constaté que je pouvais simplement compter sur l'événement "change" mentionné.

1
TheCuBeMan

Je sais que cette réponse arrive trop tard, mais voici un plug-in qui implémente selectionStart pour tous les types d'éléments, pour la plupart des navigateurs (anciens et nouveaux):

https://github.com/adelriosantiago/caret

Je l'ai mis à jour pour traiter le type="number" _ problème en utilisant la réponse de @ncohen.

0
adelriosantiago