Jak ograniczyć dane wejściowe, aby akceptować tylko liczby?

92

Używam ngChange w AngularJS do wywołania niestandardowej funkcji, która usunie wszelkie litery, które użytkownik doda do danych wejściowych.

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

Problem polega na tym, że muszę skierować dane wejściowe, które się uruchomiły, numbersOnly()aby móc usunąć wprowadzone litery. Długo i intensywnie szukałem w Google i nie mogłem znaleźć nic na ten temat.

Co mogę zrobić?

Chris Bier
źródło
To także dobre rozwiązanie, które nie pozwala na wpisywanie liter.
Himanshu Bhandari

Odpowiedzi:

104

Prosty sposób , użyj type = "number", jeśli działa to w Twoim przypadku:

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

Inny prosty sposób: ng-pattern może być również użyty do zdefiniowania wyrażenia regularnego, które ograniczy to, co jest dozwolone w polu. Zobacz także stronę „książka kucharska” o formularzach .

Hackish? sposób , $ obserwuj model ng w kontrolerze:

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

Kontroler:

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

Najlepszym sposobem jest użycie parsera $ w dyrektywie. Nie zamierzam powtarzać już dobrej odpowiedzi udzielonej przez @ pkozlowski.opensource, więc oto link: https://stackoverflow.com/a/14425022/215945

Wszystkie powyższe rozwiązania wymagają użycia modelu ng, co sprawia, że ​​wyszukiwanie jest thiszbędne.

Używanie ng-change spowoduje problemy. Zobacz AngularJS - resetowanie $ scope.value nie zmienia wartości w szablonie (losowe zachowanie)

Mark Rajcok
źródło
Skończyło się na utworzeniu dyrektywy! Dzięki za uwzględnienie najlepszego sposobu. Trochę poszukałem, ale wiele się nauczyłem!
Chris Bier
1
Czy ktoś jest w stanie rozwinąć wady do "łatwego" sposobu wymienionego jako pierwszy (typ = "liczba"), szczególnie w porównaniu z zalecanym "najlepszym" sposobem (parser $ w dyrektywie)?
Matt Welch
2
@MattWelch, późna odpowiedź, ale wadą jest obsługa przeglądarki. Również przynajmniej w Chrome type=numberautomatycznie wyświetli spinner, co może być niepożądane. Możesz ukryć spinner przez css, ale z drugiej strony nawet to może nie działać we wszystkich przeglądarkach.
Rosdi Kasim
4
Tylko dwie rzeczy, które mogą być problematyczne przy podejściu "łatwym" (typ = "liczba") to to, że 1. type = "liczba" dopuszcza znak minus (-), separator dziesiętny (./,) i notację wykładniczą (e) i 2. na urządzeniach mobilnych firmy Samsung nie można wprowadzić liczby ujemnej w polu typu = „liczba” (na klawiaturze nie ma tylko klawisza minus)
Pomocnicy,
łatwy sposób ... firefox umożliwia wprowadzanie znaków tylko w polu liczbowym. Nie aktualizuje modelu, ale wyświetla znaki
DRaehal
66

Używając ng-patternw polu tekstowym:

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

Następnie umieść to na kontrolerze

$scope.onlyNumbers = /^\d+$/;
MarkJ
źródło
To właśnie zrobiłem na podstawie odpowiedzi Marksa, ale dzięki za przykłady! Jestem pewien, że to komuś pomoże!
Chris Bier
2
działa to prawie idealnie, ale nadal pozwala na wprowadzenie „e”.
ciasteczka
Naprawdę pomaga, jeśli zmagasz się z ograniczaniem typu = "liczba" i jego długością. Rozwiązaniem jest użycie tego wzorca ng i powrót do type = "text". Bardzo uporządkowane rozwiązanie i usuwa obciążenie sprawdzania kodu pod kątem zmiany ng-change lub ng-keypress. To rozwiązanie nie pozwalało na wprowadzenie „e”, więc zakładam, że to inny problem.
PeterS
1
Wydaje mi się, że jest zależne od przeglądarki, czy nie zezwala na wprowadzanie liczb, czy nie. W przeglądarce Chrome wystarczy po prostu użyć <input type = 'number' /> i nie pozwoli na żadne wprowadzanie numeryczne, z drugiej strony Firefox z tym samym kodem HTML pozwoli na dowolne dane wejściowe, ale wyzwoli flagę nieprawidłowego wejścia, jeśli wartość nie jest liczbowa. Szukam prostego sposobu, aby uzyskać zachowanie Chrome we wszystkich przeglądarkach
steve
19

Żadne z proponowanych rozwiązań nie działało dobrze i po kilku godzinach w końcu znalazłem drogę.

Oto dyrektywa kątowa:

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

Dane wejściowe wyglądałyby następująco:

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

Wyrażenie regularne ocenia naciśnięty klawisz, a nie wartość .

Doskonale współpracuje również z wejściami, type="number"ponieważ zapobiega zmianie jego wartości, dzięki czemu klawisz nigdy nie jest wyświetlany i nie brudzi modelu.

ragnar
źródło
Aby zezwolić na negatywy,restrict-to="[0-9\-]"
Noumenon
18

Oto moja implementacja $parserrozwiązania, które @Mark Rajcok zaleca jako najlepszą metodę. Zasadniczo jest to doskonały parser $ @ pkozlowski.opensource dla odpowiedzi tekstowych, ale przepisany tak, aby zezwalał tylko na liczby. Wszystko zasługa jego, to tylko po to, aby zaoszczędzić ci 5 minut na przeczytaniu tej odpowiedzi, a następnie przepisaniu własnej:

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

Używałbyś tego w ten sposób:

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

Co ciekawe, spacje nigdy nie docierają do parsera, chyba że są otoczone alfanumerycznym, więc musisz to zrobić .trim()w razie potrzeby. Również ten parser NIE działa <input type="number">. Z jakiegoś powodu elementy nienumeryczne nigdy nie trafiają do parsera, skąd zostałyby usunięte, ale trafiają do samej kontrolki wejściowej.

Mordred
źródło
Kiedy to zaimplementowałem, otrzymałem błędy JS, jeśli model wejścia został zainicjowany bez wartości. Wprowadzenie tej zmiany spowodowało, że: var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;
Alkie
Dzięki @Alkie. Dodałem tę zmianę do dyrektywy.
Mordred
1
Musisz ustawić ng-trimna, falseaby upewnić się, że spacje dotrą do twojego parsera.
Ilya
Aby było idealnie, musisz dodać modelCtrl.$commitViewValue();między $ setViewValue (czyste); i $ render ();
ingaham
1
Dziękuję Ci! To jest po prostu niesamowite! To bardzo pomogło
iulial
4

Można to zrobić na kilka sposobów.

Możesz użyć type="number":

<input type="number" />

Alternatywnie - stworzyłem w tym celu dyrektywę wielokrotnego użytku, która używa wyrażenia regularnego.

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;
                    }
                });
            }
        };
    }]);    
}());
Peter Rasmussen
źródło
use, $ (element) .on ('input', function () {// twoja logika}); zapobiegnie to nawet wprowadzeniu niechcianej wartości
Vishal
4

Oto całkiem dobre rozwiązanie, które pozwala tylko wprowadzić liczbę do input:

<input type="text" ng-model="myText" name="inputName" onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>
Raniys
źródło
to nie pozwala mi na naciśnięcie klawisza
Delete
delete i backspace działają chociaż. Testowano w przeglądarce Firefox 76.0.1
iamjoshua
3

Wszystkie powyższe rozwiązania są dość duże, chciałem dać na to moje 2 centy.

Sprawdzam tylko, czy wprowadzona wartość jest liczbą, czy nie, i sprawdzam, czy nie jest pusta, to wszystko.

Oto html:

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

Oto JS:

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

To całkiem proste.

Wierzę, że to nie zadziała na Wklej, tylko po to, żeby było wiadomo.

Myślę, że w przypadku wklejania musiałbyś użyć zdarzenia onChange i przeanalizować cały ciąg, zupełnie inną bestię, tamme. Jest to specyficzne dla pisania.

UPDATE for Paste : po prostu dodaj tę funkcję JS:

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

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

A wejście html dodaje wyzwalacz:

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

Mam nadzieję, że to pomoże o /

Zorkind
źródło
2

Oto Plunker obsługujący każdą sytuację, której powyższa propozycja nie dotyczy.
Używając potoków $ formatters i $ parsers oraz unikając type = "number"

A oto wyjaśnienie problemów / rozwiązań (dostępne również w Plunkerze):

/*
 *
 * 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)
 *
 */
gr3g
źródło
1
   <input type="text" name="profileChildCount" id="profileChildCount" ng-model="profile.ChildCount" numeric-only maxlength="1" />

możesz użyć atrybutu tylko liczbowego.

tahsin ilhan
źródło
1

DZIESIĘTNY

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

CYFRY

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

dyrektywy kątowe do sprawdzania poprawności liczb

Angeldev
źródło
0

Wiem, że to jest stare, ale stworzyłem w tym celu dyrektywę na wypadek, gdyby ktoś szukał łatwego rozwiązania. Bardzo prosty w użyciu.

Możesz to sprawdzić tutaj .

cohenadair
źródło
0

możesz również chcieć usunąć 0 na początku danych wejściowych ... Po prostu dodaję blok if do odpowiedzi Mordreda powyżej, ponieważ nie mogę jeszcze komentować ...

  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;
          });
      }
    };
  })
syrena
źródło
0

Spróbuj tego,

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

}
Joee
źródło
0

ROZWIĄZANIE: Tworzę dyrektywę dla wszystkich danych wejściowych, liczbowych, tekstowych lub dowolnych w aplikacji, abyś mógł wprowadzić wartość i zmienić zdarzenie. Wykonaj pod kątem 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">
Seba Arce
źródło
-1

Skończyło się na utworzeniu zmodyfikowanej dyrektywy powyższego kodu, aby akceptować dane wejściowe i zmieniać format w locie ...

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

})

syrena
źródło
-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>
Rahul Sharma
źródło
1
Porzucanie kodu jest zwykle źle widziane. Proszę dodać wyjaśnienie.
rayryeng
1
aby ograniczyć klawisz naciśnij spróbuj tego - - - function Number (evt) {var charCode = (evt.which)? evt.which: event.keyCode if (charCode> 31 && (charCode <48 || charCode> 57)) return false; powrót prawda; <input type = "number" min = "0" onkeypress = "return Number (event)">
Rahul Sharma,
-1

Podstawowy HTML

<input type="number" />

Podstawowy bootstrap

<input class="form-control" type="number" value="42" id="my-id">
Amr Ibrahim
źródło
@Praveen Nie zgadzam się z tobą, pytanie nie wspomina o żadnym bootstrapie. dlaczego powinniśmy wspomnieć, że coś nie istnieje w pytaniu?
Amr Ibrahim
jeśli chcemy użyć bootstrapa <input class="form-control" type="number" >
Amr Ibrahim