web-dev-qa-db-fra.com

Vue formatée de saisie de numéro AngularJS

Je veux utiliser une entrée numérique formatée pour montrer mille points de séparation à l'utilisateur lorsqu'il tape de grands nombres. Voici le code de directive que j'ai utilisé: http://jsfiddle.net/LCZfd/3/

Lorsque j'utilise input type="text" ça marche, mais quand je veux utiliser input type="number" il est bizarrement nettoyé par quelque chose lorsque l'utilisateur tape de grands nombres.

Quel est le problème au sujet de input[number]?

29
Murat Çorlu

Comme indiqué dans les commentaires, input type="number" Ne prend en charge que des chiffres, un séparateur décimal (généralement , Ou ., Selon les paramètres régionaux) et - ou e. Vous pouvez toujours saisir ce que vous voulez, mais le navigateur supprimera tout caractère inconnu/incorrect.

Cela vous laisse 2 options:

  • utilisez type="text" et la validation de modèle comme pattern="[0-9]+([\.,][0-9]+)*" pour limiter ce que l'utilisateur peut entrer tout en formatant automatiquement la valeur comme vous le faites dans votre exemple
  • placez une superposition sur le champ d'entrée qui rend les nombres comme vous le souhaitez et permet toujours à l'utilisateur d'utiliser les contrôles d'entrée personnalisés type="number", comme illustré ici

Cette dernière solution utilise une balise <label> Supplémentaire qui contient la valeur actuelle et est masquée via CSS lorsque vous concentrez le champ de saisie.

38
S.B.

Vous devez ajouter l'attribut step à votre entrée number.

<input type="number" step="0.01" />

Cela permettra des virgules flottantes.

http://jsfiddle.net/LCZfd/1/

Je recommanderais également de revoir le fil de bogue sur les entrées number dans Firefox. Vous pouvez envisager de ne pas utiliser ce type d'entrée, car il vient juste d'être pris en charge dans ce libération de FF.

6
matthewpavkov

Toutes ces années plus tard, il n'y a toujours pas de solution HTML5 prête à l'emploi.

J'utilise <input type="tel"> Ou <input type="text"> ("Tel" fait apparaître un clavier numérique dans Android et iOS, ce qui dans certains cas est un bonus.)

Ensuite, j'avais besoin d'une directive pour:

  • filtrer les caractères non numériques
  • ajouter mille virgules de séparation comme types d'utilisateurs
  • utilisez $parsers et keyup pour régler elem.val() et $formatters pour régler l'affichage ...
  • ... dans les coulisses, attribuez à ng-model un nombre à virgule flottante

L'exemple de directive ci-dessous le fait et accepte les nombres négatifs et à virgule flottante, sauf si vous spécifiez que vous ne voulez que des nombres positifs ou entiers.

Ce n'est pas la solution complète que j'aimerais, mais je pense que cela comble le fossé.

HTML

<input type="text" ng-model="someNumber" number-input />

JAVASCRIPT

myApp.directive('numberInput', function($filter) {
  return {
    require: 'ngModel',
    link: function(scope, elem, attrs, ngModelCtrl) {

      ngModelCtrl.$formatters.Push(function(modelValue) {
        return setDisplayNumber(modelValue, true);
      });

      // it's best to change the displayed text using elem.val() rather than
      // ngModelCtrl.$setViewValue because the latter will re-trigger the parser
      // and not necessarily in the correct order with the changed value last.
      // see http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/
      // for an explanation of how ngModelCtrl works.
      ngModelCtrl.$parsers.Push(function(viewValue) {
        setDisplayNumber(viewValue);
        return setModelNumber(viewValue);
      });

      // occasionally the parser chain doesn't run (when the user repeatedly 
      // types the same non-numeric character)
      // for these cases, clean up again half a second later using "keyup"
      // (the parser runs much sooner than keyup, so it's better UX to also do it within parser
      // to give the feeling that the comma is added as they type)
      elem.bind('keyup focus', function() {
        setDisplayNumber(elem.val());
      });
      function setDisplayNumber(val, formatter) {
        var valStr, displayValue;

        if (typeof val === 'undefined') {
          return 0;
        }

        valStr = val.toString();
        displayValue = valStr.replace(/,/g, '').replace(/[A-Za-z]/g, '');
        displayValue = parseFloat(displayValue);
        displayValue = (!isNaN(displayValue)) ? displayValue.toString() : '';

        // handle leading character -/0
        if (valStr.length === 1 && valStr[0] === '-') {
          displayValue = valStr[0];
        } else if (valStr.length === 1 && valStr[0] === '0') {
          displayValue = '';
        } else {
          displayValue = $filter('number')(displayValue);
        }
        // handle decimal
        if (!attrs.integer) {
          if (displayValue.indexOf('.') === -1) {
            if (valStr.slice(-1) === '.') {
              displayValue += '.';
            } else if (valStr.slice(-2) === '.0') {
              displayValue += '.0';
            } else if (valStr.slice(-3) === '.00') {
              displayValue += '.00';
            }
          } // handle last character 0 after decimal and another number
          else {
            if (valStr.slice(-1) === '0') {
              displayValue += '0';
            }
          }
        }

        if (attrs.positive && displayValue[0] === '-') {
          displayValue = displayValue.substring(1);
        }

        if (typeof formatter !== 'undefined') {
          return (displayValue === '') ? 0 : displayValue;
        } else {
          elem.val((displayValue === '0') ? '' : displayValue);
        }
      }
      function setModelNumber(val) {
        var modelNum = val.toString().replace(/,/g, '').replace(/[A-Za-z]/g, '');
        modelNum = parseFloat(modelNum);
        modelNum = (!isNaN(modelNum)) ? modelNum : 0;
        if (modelNum.toString().indexOf('.') !== -1) {
          modelNum = Math.round((modelNum + 0.00001) * 100) / 100;
        }
        if (attrs.positive) {
          modelNum = Math.abs(modelNum);
        }
        return modelNum;
      }
    }
  };
});

https://jsfiddle.net/benlk/4dto9738/

6
BenK

vous pouvez essayer cela, j'ai modifié la directive que j'ai vue ici ... Comment puis-je restreindre une entrée pour n'accepter que des nombres? ...

voici la directive modifiée que j'ai faite ... Cette directive utilise l'événement keyup pour modifier l'entrée à la volée ...

.directive('numericOnly', function($filter) {
 return {
  require: 'ngModel',
  link: function(scope, element, attrs, modelCtrl) {

       element.bind('keyup', function (inputValue, e) {
         var strinput = modelCtrl.$$rawModelValue;
         //filter user input
         var transformedInput = strinput ? strinput.replace(/[^,\d.-]/g,'') : null;
         //remove trailing 0
         if(transformedInput.charAt(0) <= '0'){
           transformedInput = null;
           modelCtrl.$setViewValue(transformedInput);
           modelCtrl.$render();
         }else{
           var decimalSplit = transformedInput.split(".")
           var intPart = decimalSplit[0];
           var decPart = decimalSplit[1];
           //remove previously formated number
           intPart = intPart.replace(/,/g, "");
           //split whole number into array of 3 digits
           if(intPart.length > 3){
             var intDiv = Math.floor(intPart.length / 3);
             var strfraction = [];
             var i = intDiv,
                 j = 3;

             while(intDiv > 0){
               strfraction[intDiv] = intPart.slice(intPart.length-j,intPart.length - (j - 3));
               j=j+3;
               intDiv--;
             }
             var k = j-3;
             if((intPart.length-k) > 0){
               strfraction[0] = intPart.slice(0,intPart.length-k);
             }
           }
           //join arrays
           if(strfraction == undefined){ return;}
             var currencyformat = strfraction.join(',');
             //check for leading comma
             if(currencyformat.charAt(0)==','){
               currencyformat = currencyformat.slice(1);
             }

             if(decPart ==  undefined){
               modelCtrl.$setViewValue(currencyformat);
               modelCtrl.$render();
               return;
             }else{
               currencyformat = currencyformat + "." + decPart.slice(0,2);
               modelCtrl.$setViewValue(currencyformat);
               modelCtrl.$render();
             }
         }
        });
  }

};

vous l'utilisez comme ça ...

<input type="text" ng-model="amountallocated" id="amountallocated" numeric-only />
2
sireken

Vous ne pouvez pas utiliser de valeurs avec , car type=number ne prend que des nombres, l'ajout d'une virgule en fait une chaîne.

Voir http://jsfiddle.net/LCZfd/5

Vous feriez mieux de faire vos propres contrôles si vous voulez des virgules. Un avec une vraie valeur (le nombre) et une valeur d'affichage (la chaîne).

2
Jahed