Come si limita un input ad accettare solo numeri?


92

Sto usando ngChange in AngularJS per attivare una funzione personalizzata che rimuoverà tutte le lettere che l'utente aggiunge all'input.

<input type="text" name="inputName" data-ng-change="numbersOnly()"/>

Il problema è che devo indirizzare l'input che si è attivato in numbersOnly()modo da poter rimuovere le lettere inserite. Ho cercato a lungo su Google e non sono riuscito a trovare nulla al riguardo.

Cosa posso fare?


Questa è anche una buona soluzione, che non consente di inserire lettere.
Himanshu Bhandari

Risposte:


104

In modo semplice , usa type = "number" se funziona per il tuo caso d'uso:

<input type="number" ng-model="myText" name="inputName">

Un altro modo semplice: ng-pattern può anche essere usato per definire una regex che limiterà ciò che è consentito nel campo. Vedi anche la pagina "ricettario" sui moduli .

Hackish? way , $ guarda il modello ng nel tuo controller:

<input type="text"  ng-model="myText" name="inputName">

Controller:

$scope.$watch('myText', function() {
   // put numbersOnly() logic here, e.g.:
   if ($scope.myText  ... regex to look for ... ) {
      // strip out the non-numbers
   }
})

Il modo migliore , usa un $ parser in una direttiva. Non ripeterò la già buona risposta fornita da @ pkozlowski.opensource, quindi ecco il link: https://stackoverflow.com/a/14425022/215945

Tutte le soluzioni di cui sopra comportano l'uso di ng-model, che rende thissuperflua la ricerca .

L'uso di ng-change causerà problemi. Vedi AngularJS - il ripristino di $ scope.value non cambia il valore nel modello (comportamento casuale)


Finito per creare una direttiva! Grazie per aver incluso il modo migliore. Ho fatto un po 'di ricerche ma ho imparato molto!
Chris Bier

1
Qualcuno in grado di espandere gli aspetti negativi al modo "facile" elencato per primo (tipo = "numero"), in particolare rispetto al modo "migliore" consigliato ($ parser nella direttiva)?
Matt Welch

2
@ MattWelch, risposta in ritardo ma lo svantaggio è il supporto del browser. Anche in Chrome, almeno, type=numberverrà visualizzato automaticamente lo spinner che potrebbe essere indesiderabile. Puoi nascondere lo spinner tramite CSS, ma anche questo potrebbe non funzionare su tutti i browser.
Rosdi Kasim

4
Solo due cose che potrebbero essere problematiche con l'approccio "facile" (tipo = "numero") sono che 1. tipo = "numero" consente il segno negativo (-), il separatore decimale (./,) e la notazione esponenziale (e) e 2. sui dispositivi mobili Samsung non è possibile inserire un numero negativo in un campo type = "number" (semplicemente non c'è il tasto meno sulla tastiera)
Assistenti

modo semplice ... firefox consente di inserire caratteri in un campo solo numerico. Non aggiorna il modello, ma mostra i caratteri
DRaehal

66

Utilizzo ng-patternnel campo di testo:

<input type="text"  ng-model="myText" name="inputName" ng-pattern="onlyNumbers">

Quindi includilo nel controller

$scope.onlyNumbers = /^\d+$/;

Questo è quello che ho finito per fare sulla base della risposta di Marks, grazie per gli esempi! Sono sicuro che aiuterà qualcuno!
Chris Bier,

2
funziona quasi perfettamente, ma consente comunque di inserire "e".
biscotti

Davvero aiuta se stai lottando con la limitazione di tipo = "numero" e la sua lunghezza. La soluzione è usare questo modello ng e tornare a type = "text". Soluzione molto ordinata e rimuove un carico di controllo del codice per ng-change o ng-keypress. Questa soluzione non consentiva l'inserimento di "e", quindi presumo sia un altro problema.
PeterS

1
Mi sembra che sia specifico del browser se non consentirà o meno alcuna immissione numerica. Su Chrome è sufficiente utilizzare <input type = 'number' /> e non consentirà nessuna immissione numerica, Firefox invece con lo stesso Html consentirà qualsiasi input ma attiva il flag di input non valido se il valore non è numerico. Sto cercando un modo semplice per ottenere il comportamento di Chrome su tutti i browser
steve

19

Nessuna delle soluzioni proposte ha funzionato bene per me e dopo un paio d'ore ho finalmente trovato la strada.

Questa è la direttiva angolare:

angular.module('app').directive('restrictTo', function() {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var re = RegExp(attrs.restrictTo);
            var exclude = /Backspace|Enter|Tab|Delete|Del|ArrowUp|Up|ArrowDown|Down|ArrowLeft|Left|ArrowRight|Right/;

            element[0].addEventListener('keydown', function(event) {
                if (!exclude.test(event.key) && !re.test(event.key)) {
                    event.preventDefault();
                }
            });
        }
    }
});

E l'input sarebbe simile a:

<input type="number" min="0" name="inputName" ng-model="myModel" restrict-to="[0-9]">

L'espressione regolare valuta il tasto premuto, non il valore .

Funziona perfettamente anche con gli input type="number"perché impedisce di modificarne il valore, quindi la chiave non viene mai visualizzata e non si confonde con il modello.


Per consentire negativi,restrict-to="[0-9\-]"
Noumenon

18

Ecco la mia implementazione della $parsersoluzione che @Mark Rajcok consiglia come metodo migliore. È essenzialmente l' eccellente $ parser di @ pkozlowski.opensource per la risposta del testo, ma riscritto per consentire solo valori numerici . Tutto il merito va a lui, questo è solo per farti risparmiare i 5 minuti di lettura di quella risposta e poi di riscrivere la tua:

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

            modelCtrl.$parsers.push(function (inputValue) {
                var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;

                if (transformedInput!=inputValue) {
                    modelCtrl.$setViewValue(transformedInput);
                    modelCtrl.$render();
                }

                return transformedInput;
            });
        }
    };
});

E lo useresti in questo modo:

<input type="text" name="number" ng-model="num_things" numeric-only>

È interessante notare che gli spazi non raggiungono mai il parser a meno che non siano circondati da un alfanumerico, quindi dovresti farlo .trim()se necessario. Inoltre, questo parser NON funziona <input type="number">. Per qualche ragione, non numerici non rendono al parser dov'erano essere rimossi, ma farlo lo rendono nel controllo di input stessa.


Quando l'ho implementato, ho ricevuto errori JS se il modello di input è stato inizializzato senza un valore. Apportare questa modifica ha risolto che: var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;
Alkie

Grazie @Alkie. Ho aggiunto quella modifica alla direttiva.
Mordred

1
Devi impostare ng-trimsu falseper assicurarti che gli spazi raggiungano il tuo parser.
Ilya

Per renderlo perfetto è necessario aggiungere modelCtrl.$commitViewValue();tra $ setViewValue (clean); e $ render ();
ingaham

1
Grazie! Questo è semplicemente fantastico! Ha aiutato molto
iulial

4

Ci sono alcuni modi per farlo.

Potresti usare type="number":

<input type="number" />

In alternativa, ho creato una direttiva riutilizzabile per questo che utilizza un'espressione regolare.

HTML

<div ng-app="myawesomeapp">
    test: <input restrict-input="^[0-9-]*$" maxlength="20" type="text" class="test" />
</div>

Javascript

;(function(){
    var app = angular.module('myawesomeapp',[])
    .directive('restrictInput', [function(){

        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                var ele = element[0];
                var regex = RegExp(attrs.restrictInput);
                var value = ele.value;

                ele.addEventListener('keyup',function(e){
                    if (regex.test(ele.value)){
                        value = ele.value;
                    }else{
                        ele.value = value;
                    }
                });
            }
        };
    }]);    
}());

usa, $ (elemento) .on ('input', function () {// tua logica}); questo impedirà anche di inserire il valore indesiderato
Vishal

4

Ecco una soluzione abbastanza buona per consentire solo il numero di immissione a input:

<input type="text" ng-model="myText" name="inputName" onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>

questo non mi permette di premere
Canc

cancella e backspace funziona però. Testato su Firefox 76.0.1
iamjoshua

3

Tutte le soluzioni di cui sopra sono abbastanza grandi, volevo dare i miei 2 centesimi su questo.

Sto solo controllando se il valore inserito è un numero o meno e controllando se non è vuoto, tutto qui.

Ecco l'html:

<input type="text" ng-keypress="CheckNumber()"/>

Ecco il JS:

$scope.CheckKey = function () {
    if (isNaN(event.key) || event.key === ' ' || event.key === '') {
        event.returnValue = '';
    }
};

È abbastanza semplice.

Credo che questo non funzionerà su Paste tho, solo così è noto.

Per Paste, penso che dovresti usare l'evento onChange e analizzare l'intera stringa, un'altra bestia il tamme. Questo è specifico per la digitazione.

AGGIORNA per Incolla : aggiungi questa funzione JS:

$scope.CheckPaste = function () {
    var paste = event.clipboardData.getData('text');

    if (isNaN(paste)) {
        event.preventDefault();
        return false;
    }
};

E l'input html aggiunge il trigger:

<input type="text" ng-paste="CheckPaste()"/>

Spero che questo aiuti o /


2

Ecco un Plunker che gestisce qualsiasi situazione sopra proposta non gestita .
Usando $ formatters e $ parser pipeline ed evitando type = "number"

Ed ecco la spiegazione dei problemi / soluzioni (disponibile anche nel Plunker):

/*
 *
 * Limit input text for floating numbers.
 * It does not display characters and can limit the Float value to X numbers of integers and X numbers of decimals.
 * min and max attributes can be added. They can be Integers as well as Floating values.
 *
 * value needed    |    directive
 * ------------------------------------
 * 55              |    max-integer="2"
 * 55.55           |    max-integer="4" decimal="2" (decimals are substracted from total length. Same logic as database NUMBER type)
 *
 *
 * Input type="number" (HTML5)
 *
 * Browser compatibility for input type="number" :
 * Chrome : - if first letter is a String : allows everything
 *          - if first letter is a Integer : allows [0-9] and "." and "e" (exponential)
 * Firefox : allows everything
 * Internet Explorer : allows everything
 *
 * Why you should not use input type="number" :
 * When using input type="number" the $parser pipeline of ngModel controller won't be able to access NaN values.
 * For example : viewValue = '1e'  -> $parsers parameter value = "".
 * This is because undefined values are not allowes by default (which can be changed, but better not do it)
 * This makes it impossible to modify the view and model value; to get the view value, pop last character, apply to the view and return to the model.
 *
 * About the ngModel controller pipelines :
 * view value -> $parsers -> model value
 * model value -> $formatters -> view value
 *
 * About the $parsers pipeline :
 * It is an array of functions executed in ascending order.
 * When used with input type="number" :
 * This array has 2 default functions, one of them transforms the datatype of the value from String to Number.
 * To be able to change the value easier (substring), it is better to have access to a String rather than a Number.
 * To access a String, the custom function added to the $parsers pipeline should be unshifted rather than pushed.
 * Unshift gives the closest access to the view.
 *
 * About the $formatters pipeline :
 * It is executed in descending order
 * When used with input type="number"
 * Default function transforms the value datatype from Number to String.
 * To access a String, push to this pipeline. (push brings the function closest to the view value)
 *
 * The flow :
 * When changing ngModel where the directive stands : (In this case only the view has to be changed. $parsers returns the changed model)
 *     -When the value do not has to be modified :
 *     $parsers -> $render();
 *     -When the value has to be modified :
 *     $parsers(view value) --(does view needs to be changed?) -> $render();
 *       |                                  |
 *       |                     $setViewValue(changedViewValue)
 *       |                                  |
 *       --<-------<---------<--------<------
 *
 * When changing ngModel where the directive does not stand :
 *     - When the value does not has to be modified :
 *       -$formatters(model value)-->-- view value
 *     -When the value has to be changed
 *       -$formatters(model vale)-->--(does the value has to be modified) -- (when loop $parsers loop is finished, return modified value)-->view value
 *                                              |
 *                                  $setViewValue(notChangedValue) giving back the non changed value allows the $parsers handle the 'bad' value
 *                                               |                  and avoids it to think the value did not changed
 *                Changed the model <----(the above $parsers loop occurs)
 *
 */

1
   <input type="text" name="profileChildCount" id="profileChildCount" ng-model="profile.ChildCount" numeric-only maxlength="1" />

puoi utilizzare l'attributo solo numerico.


1

DECIMALE

directive('decimal', function() {
                return {
                    require: 'ngModel',
                    restrict: 'A',
                    link: function(scope, element, attr, ctrl) {
                        function inputValue(val) {
                            if (val) {
                                var digits = val.replace(/[^0-9.]/g, '');

                                if (digits.split('.').length > 2) {
                                    digits = digits.substring(0, digits.length - 1);
                                }

                                if (digits !== val) {
                                    ctrl.$setViewValue(digits);
                                    ctrl.$render();
                                }
                                return parseFloat(digits);
                            }
                            return "";
                        }
                        ctrl.$parsers.push(inputValue);
                    }
                };
            });

CIFRE

directive('entero', function() {
            return {
                require: 'ngModel',
                restrict: 'A',
                link: function(scope, element, attr, ctrl) {
                    function inputValue(val) {
                        if (val) {
                            var value = val + ''; //convert to string
                            var digits = value.replace(/[^0-9]/g, '');

                            if (digits !== value) {
                                ctrl.$setViewValue(digits);
                                ctrl.$render();
                            }
                            return parseInt(digits);
                        }
                        return "";
                    }
                    ctrl.$parsers.push(inputValue);
                }
            };
        });

direttive angolari per convalidare i numeri


0

So che è vecchio, ma ho creato una direttiva per questo scopo nel caso qualcuno stia cercando una soluzione facile. Molto semplice da usare.

Puoi verificarlo qui .


0

potresti anche voler rimuovere lo 0 all'inizio dell'input ... aggiungo semplicemente un blocco if alla risposta di Mordred sopra perché non posso ancora fare un commento ...

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

          modelCtrl.$parsers.push(function (inputValue) {
              var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;

              if (transformedInput!=inputValue) {
                  modelCtrl.$setViewValue(transformedInput);
                  modelCtrl.$render();
              }
              //clear beginning 0
              if(transformedInput == 0){
                modelCtrl.$setViewValue(null);
                modelCtrl.$render();
              }
              return transformedInput;
          });
      }
    };
  })

0

Prova questo,

<input ng-keypress="validation($event)">

 function validation(event) {
    var theEvent = event || window.event;
    var key = theEvent.keyCode || theEvent.which;
    key = String.fromCharCode(key);
    var regex = /[0-9]|\./;
    if (!regex.test(key)) {
        theEvent.returnValue = false;
        if (theEvent.preventDefault) theEvent.preventDefault();
    }

}

0

SOLUZIONE: creo una direttiva per tutti gli input, numero, testo o qualsiasi, nell'app, in modo da poter inserire un valore e modificare l'evento. Fare per angolare 6

 import { Directive, ElementRef, HostListener, Input } from '@angular/core';

 @Directive({
// tslint:disable-next-line:directive-selector
selector: 'input[inputType]'
})
  export class InputTypeDirective {
 constructor(private _el: ElementRef) {}

 @Input() inputType: string;
 // tipos: number, letter, cuit, tel

@HostListener('input', ['$event']) onInputChange(event) {
if (!event.data) {
  return;
}

switch (this.inputType) {
  case 'number': {
    const initalValue = this._el.nativeElement.value;
    this._el.nativeElement.value = initalValue.replace(/[^0-9]*/g, '');
    if (initalValue !== this._el.nativeElement.value) {
      event.stopPropagation();
    }
     break;
          }
       case 'text': {
        const result = event.data.match(/[^a-zA-Z Ññ]*/g);
        if (result[0] !== '') {
           const initalValue = this._el.nativeElement.value;
           this._el.nativeElement.value = initalValue.replace(
          /[^a-zA-Z Ññ]*/g,
           ''
         );
           event.stopPropagation();
        }
        break;
    }
        case 'tel':
          case 'cuit': {
         const initalValue = this._el.nativeElement.value;
      this._el.nativeElement.value = initalValue.replace(/[^0-9-]*/g, '');
       if (initalValue !== this._el.nativeElement.value) {
         event.stopPropagation();
       }
     }
   }
  }
   }

HTML

     <input matInput inputType="number" [formControlName]="field.name" [maxlength]="field.length" [placeholder]="field.label | translate"  type="text" class="filter-input">

-1

Ho finito per creare una direttiva modificata del codice sopra per accettare l'input e cambiare il formato al volo ...

.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();
                 }
             }
            });
      }
  };

})


-1
<input type="text" ng-model="employee.age" valid-input input-pattern="[^0-9]+" placeholder="Enter an age" />

<script>
var app = angular.module('app', []);

app.controller('dataCtrl', function($scope) {
});

app.directive('validInput', function() {
  return {
    require: '?ngModel',
    scope: {
      "inputPattern": '@'
    },
    link: function(scope, element, attrs, ngModelCtrl) {

      var regexp = null;

      if (scope.inputPattern !== undefined) {
        regexp = new RegExp(scope.inputPattern, "g");
      }

      if(!ngModelCtrl) {
        return;
      }

      ngModelCtrl.$parsers.push(function(val) {
        if (regexp) {
          var clean = val.replace(regexp, '');
          if (val !== clean) {
            ngModelCtrl.$setViewValue(clean);
            ngModelCtrl.$render();
          }
          return clean;
        }
        else {
          return val;
        }

      });

      element.bind('keypress', function(event) {
        if(event.keyCode === 32) {
          event.preventDefault();
        }
      });
    }
}}); </script>

1
Il code dumping è generalmente disapprovato. Per favore aggiungi qualche spiegazione.
rayryeng,

1
per limitare la pressione del tasto prova questo - - - funzione Number (evt) {var charCode = (evt.which)? evt.which: event.keyCode if (charCode> 31 && (charCode <48 || charCode> 57)) return false; restituire vero; <input type = "number" min = "0" onkeypress = "return Number (event)">
Rahul Sharma

-1

HTML di base

<input type="number" />

Bootstrap di base

<input class="form-control" type="number" value="42" id="my-id">

@ Praveen non sono d'accordo con te, la domanda non menziona alcun bootstrap. perché dovremmo menzionare qualcosa che non esiste nella domanda?
Amr Ibrahim

se vogliamo usare bootstrap <input class="form-control" type="number" >
Amr Ibrahim
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.