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ć?
javascript
angularjs
angularjs-directive
Chris Bier
źródło
źródło
Odpowiedzi:
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
this
zbędne.Używanie ng-change spowoduje problemy. Zobacz AngularJS - resetowanie $ scope.value nie zmienia wartości w szablonie (losowe zachowanie)
źródło
type=number
automatycznie 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.Używając
ng-pattern
w polu tekstowym:<input type="text" ng-model="myText" name="inputName" ng-pattern="onlyNumbers">
Następnie umieść to na kontrolerze
$scope.onlyNumbers = /^\d+$/;
źródło
Ż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.źródło
restrict-to="[0-9\-]"
Oto moja implementacja
$parser
rozwią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.źródło
var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;
ng-trim
na,false
aby upewnić się, że spacje dotrą do twojego parsera.modelCtrl.$commitViewValue();
między $ setViewValue (czyste); i $ render ();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; } }); } }; }]); }());
źródło
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'/>
źródło
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 /
źródło
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) * */
źródło
<input type="text" name="profileChildCount" id="profileChildCount" ng-model="profile.ChildCount" numeric-only maxlength="1" />
możesz użyć atrybutu tylko liczbowego.
źródło
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
źródło
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 .
źródło
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; }); } }; })
źródło
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(); } }
źródło
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">
źródło
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(); } } }); } };
})
źródło
<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>
źródło
Podstawowy HTML
<input type="number" />
Podstawowy bootstrap
<input class="form-control" type="number" value="42" id="my-id">
źródło
<input class="form-control" type="number" >