W Angular 2, jak mogę zamaskować pole wejściowe (pole tekstowe) tak, aby akceptowało tylko liczby, a nie znaki alfabetyczne?
Mam następujące dane wejściowe HTML:
<input
type="text"
*ngSwitchDefault
class="form-control"
(change)="onInputChange()"
[(ngModel)]="config.Value"
(focus)="handleFocus($event)"
(blur)="handleBlur($event)"
/>
Powyższe dane wejściowe to ogólne dane wejściowe, które mogą być używane jako proste pole tekstowe lub jako pole numeryczne, na przykład w celu wyświetlenia roku.
Używając Angulara 2, jak mogę użyć tej samej kontrolki wejściowej i zastosować jakiś rodzaj filtru / maski w tym polu, tak aby akceptował tylko liczby?
Jakie są różne sposoby, w jakie mogę to osiągnąć?
Uwaga: Muszę to osiągnąć używając tylko pola tekstowego i nie używając typu numeru wejściowego.
html
angular
input
angularjs-directive
Aniruddha Pondhe
źródło
źródło
Odpowiedzi:
Możesz użyć dyrektyw angular2. Plunkr
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ selector: '[OnlyNumber]' }) export class OnlyNumber { constructor(private el: ElementRef) { } @Input() OnlyNumber: boolean; @HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if (this.OnlyNumber) { if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 || // Allow: Ctrl+A (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+C (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+V (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+X (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) || // Allow: home, end, left, right (e.keyCode >= 35 && e.keyCode <= 39)) { // let it happen, don't do anything return; } // Ensure that it is a number and stop the keypress if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { e.preventDefault(); } } } }
i musisz wpisać nazwę dyrektywy w swoim wejściu jako atrybut
<input OnlyNumber="true" />
nie zapomnij napisać swojej dyrektywy w tablicy deklaracji swojego modułu.
Używając wyrażenia regularnego, nadal potrzebujesz klawiszy funkcyjnych
export class OnlyNumber { regexStr = '^[0-9]*$'; constructor(private el: ElementRef) { } @Input() OnlyNumber: boolean; @HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if (this.OnlyNumber) { if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 || // Allow: Ctrl+A (e.keyCode == 65 && e.ctrlKey === true) || // Allow: Ctrl+C (e.keyCode == 67 && e.ctrlKey === true) || // Allow: Ctrl+V (e.keyCode == 86 && e.ctrlKey === true) || // Allow: Ctrl+X (e.keyCode == 88 && e.ctrlKey === true) || // Allow: home, end, left, right (e.keyCode >= 35 && e.keyCode <= 39)) { // let it happen, don't do anything return; } let ch = String.fromCharCode(e.keyCode); let regEx = new RegExp(this.regexStr); if(regEx.test(ch)) return; else e.preventDefault(); } } }
źródło
(e.keyCode == 86 && e.ctrlKey === true)
do warunków, kopia działa, ale nie działa pastaJeśli nie chcesz dyrektywy
https://stackblitz.com/edit/numeric-only
w komponencie.html
<input (keypress)="numberOnly($event)" type="text">
w component.ts
export class AppComponent { numberOnly(event): boolean { const charCode = (event.which) ? event.which : event.keyCode; if (charCode > 31 && (charCode < 48 || charCode > 57)) { return false; } return true; } }
źródło
Wiem, że to stare pytanie, ale ponieważ jest to powszechna funkcja, chcę podzielić się modyfikacjami, które wprowadziłem:
Zastąp ciągi, takie jak „.33” i „33”. dla poprawnych wersji: 0.33 i 33.0
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ selector: '[NumbersOnly]' }) export class NumbersOnly { @Input() allowDecimals: boolean = true; @Input() allowSign: boolean = false; @Input() decimalSeparator: string = '.'; previousValue: string = ''; // -------------------------------------- // Regular expressions integerUnsigned: string = '^[0-9]*$'; integerSigned: string = '^-?[0-9]+$'; decimalUnsigned: string = '^[0-9]+(.[0-9]+)?$'; decimalSigned: string = '^-?[0-9]+(.[0-9]+)?$'; /** * Class constructor * @param hostElement */ constructor(private hostElement: ElementRef) { } /** * Event handler for host's change event * @param e */ @HostListener('change', ['$event']) onChange(e) { this.validateValue(this.hostElement.nativeElement.value); } /** * Event handler for host's paste event * @param e */ @HostListener('paste', ['$event']) onPaste(e) { // get and validate data from clipboard let value = e.clipboardData.getData('text/plain'); this.validateValue(value); e.preventDefault(); } /** * Event handler for host's keydown event * @param event */ @HostListener('keydown', ['$event']) onKeyDown(e: KeyboardEvent) { let cursorPosition: number = e.target['selectionStart']; let originalValue: string = e.target['value']; let key: string = this.getName(e); let controlOrCommand = (e.ctrlKey === true || e.metaKey === true); let signExists = originalValue.includes('-'); let separatorExists = originalValue.includes(this.decimalSeparator); // allowed keys apart from numeric characters let allowedKeys = [ 'Backspace', 'ArrowLeft', 'ArrowRight', 'Escape', 'Tab' ]; // when decimals are allowed, add // decimal separator to allowed codes when // its position is not close to the the sign (-. and .-) let separatorIsCloseToSign = (signExists && cursorPosition <= 1); if (this.allowDecimals && !separatorIsCloseToSign && !separatorExists) { if (this.decimalSeparator == '.') allowedKeys.push('.'); else allowedKeys.push(','); } // when minus sign is allowed, add its // key to allowed key only when the // cursor is in the first position, and // first character is different from // decimal separator let firstCharacterIsSeparator = (originalValue.charAt(0) != this.decimalSeparator); if (this.allowSign && !signExists && firstCharacterIsSeparator && cursorPosition == 0) { allowedKeys.push('-'); } // allow some non-numeric characters if (allowedKeys.indexOf(key) != -1 || // Allow: Ctrl+A and Command+A (key == 'a' && controlOrCommand) || // Allow: Ctrl+C and Command+C (key == 'c' && controlOrCommand) || // Allow: Ctrl+V and Command+V (key == 'v' && controlOrCommand) || // Allow: Ctrl+X and Command+X (key == 'x' && controlOrCommand)) { // let it happen, don't do anything return; } // save value before keydown event this.previousValue = originalValue; // allow number characters only let isNumber = (new RegExp(this.integerUnsigned)).test(key); if (isNumber) return; else e.preventDefault(); } /** * Test whether value is a valid number or not * @param value */ validateValue(value: string): void { // choose the appropiate regular expression let regex: string; if (!this.allowDecimals && !this.allowSign) regex = this.integerUnsigned; if (!this.allowDecimals && this.allowSign) regex = this.integerSigned; if (this.allowDecimals && !this.allowSign) regex = this.decimalUnsigned; if (this.allowDecimals && this.allowSign) regex = this.decimalSigned; // when a numbers begins with a decimal separator, // fix it adding a zero in the beginning let firstCharacter = value.charAt(0); if (firstCharacter == this.decimalSeparator) value = 0 + value; // when a numbers ends with a decimal separator, // fix it adding a zero in the end let lastCharacter = value.charAt(value.length-1); if (lastCharacter == this.decimalSeparator) value = value + 0; // test number with regular expression, when // number is invalid, replace it with a zero let valid: boolean = (new RegExp(regex)).test(value); this.hostElement.nativeElement['value'] = valid ? value : 0; } /** * Get key's name * @param e */ getName(e): string { if (e.key) { return e.key; } else { // for old browsers if (e.keyCode && String.fromCharCode) { switch (e.keyCode) { case 8: return 'Backspace'; case 9: return 'Tab'; case 27: return 'Escape'; case 37: return 'ArrowLeft'; case 39: return 'ArrowRight'; case 188: return ','; case 190: return '.'; case 109: return '-'; // minus in numbpad case 173: return '-'; // minus in alphabet keyboard in firefox case 189: return '-'; // minus in alphabet keyboard in chrome default: return String.fromCharCode(e.keyCode); } } } }
Stosowanie:
<input NumbersOnly [allowDecimals]="true" [allowSign]="true" type="text">
źródło
Chciałbym oprzeć się na odpowiedzi udzielonej przez @omeralper, która moim zdaniem była dobrą podstawą do solidnego rozwiązania.
Proponuję uproszczoną i aktualną wersję z najnowszymi standardami sieciowymi. Należy zauważyć, że kod event.keycode został usunięty ze standardów sieciowych, a przyszłe aktualizacje przeglądarki mogą go już nie obsługiwać. Zobacz https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
Ponadto metoda
String.fromCharCode(e.keyCode);
nie gwarantuje, że keyCode odnoszący się do klawisza wciskanego przez użytkownika jest odwzorowywany na oczekiwaną literę identyfikowaną na klawiaturze użytkownika, ponieważ różne konfiguracje klawiatury spowodują, że dany kod klawisza będzie miał różne znaki. Użycie tego spowoduje wprowadzenie błędów, które są trudne do zidentyfikowania i mogą łatwo uszkodzić funkcjonalność niektórych użytkowników. Raczej proponuję użycie event.key, zobacz dokumentację tutaj https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
Ponadto chcemy, aby wynikowe dane wyjściowe były poprawnymi liczbami dziesiętnymi. Oznacza to, że należy zaakceptować liczby 1, 11.2, 5000.2341234, ale nie należy przyjąć wartości 1.1.2.
Zauważ, że w moim rozwiązaniu wykluczam funkcję wycinania, kopiowania i wklejania, ponieważ otwiera okna w poszukiwaniu błędów, zwłaszcza gdy ludzie wklejają niechciany tekst w powiązanych polach. To wymagałoby procesu czyszczenia w programie obsługi klucza; co nie jest przedmiotem tego wątku.
Oto rozwiązanie, które proponuję.
import { Directive, ElementRef, HostListener } from '@angular/core'; @Directive({ selector: '[myNumberOnly]' }) export class NumberOnlyDirective { // Allow decimal numbers. The \. is only allowed once to occur private regex: RegExp = new RegExp(/^[0-9]+(\.[0-9]*){0,1}$/g); // Allow key codes for special events. Reflect : // Backspace, tab, end, home private specialKeys: Array<string> = [ 'Backspace', 'Tab', 'End', 'Home' ]; constructor(private el: ElementRef) { } @HostListener('keydown', [ '$event' ]) onKeyDown(event: KeyboardEvent) { // Allow Backspace, tab, end, and home keys if (this.specialKeys.indexOf(event.key) !== -1) { return; } // Do not use event.keycode this is deprecated. // See: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode let current: string = this.el.nativeElement.value; // We need this because the current value on the DOM element // is not yet updated with the value from this event let next: string = current.concat(event.key); if (next && !String(next).match(this.regex)) { event.preventDefault(); } } }
źródło
Bardziej zwięzłe rozwiązanie. Wypróbuj tę dyrektywę.
Może być również używany, jeśli używasz ReactiveForms.
export class NumberOnlyDirective { private el: NgControl; constructor(private ngControl: NgControl) { this.el = ngControl; } // Listen for the input event to also handle copy and paste. @HostListener('input', ['$event.target.value']) onInput(value: string) { // Use NgControl patchValue to prevent the issue on validation this.el.control.patchValue(value.replace(/[^0-9]/g, '')); } }
Użyj go na swoich wejściach w ten sposób:
<input matInput formControlName="aNumberField" numberOnly>
źródło
<input type="text" (keypress)="keyPress($event)"> keyPress(event: any) { const pattern = /[0-9\+\-\ ]/; let inputChar = String.fromCharCode(event.charCode); if (event.keyCode != 8 && !pattern.test(inputChar)) { event.preventDefault(); } }
źródło
Zamiast tekstu musisz użyć type = "number". Możesz również określić numery maksymalne i minimalne
<input type="number" name="quantity" min="1" max="5">
źródło
type="number"
jest to, że akceptuje znakie
jako część notacji naukowejmożesz to osiągnąć w ten sposób
<input type="text" pInputText (keypress)="onlyNumberKey($event)" maxlength="3"> onlyNumberKey(event) { return (event.charCode == 8 || event.charCode == 0) ? null : event.charCode >= 48 && event.charCode <= 57; } //for Decimal you can use this as onlyDecimalNumberKey(event) { let charCode = (event.which) ? event.which : event.keyCode; if (charCode != 46 && charCode > 31 && (charCode < 48 || charCode > 57)) return false; return true; }
mam nadzieję, że to ci pomoże.
źródło
Możesz użyć wyrażenia regularnego:
<input type="text" (keypress)="numericOnly($event)"> numericOnly(event): boolean { let patt = /^([0-9])$/; let result = patt.test(event.key); return result; }
źródło
Użyj
pattern
atrybutu do wprowadzania danych, jak poniżej:<input type="text" pattern="[0-9]+" >
źródło
Wiem, że ma wiele odpowiedzi, ale musiałem poradzić sobie z następującymi (których żadna z odpowiedzi nie wydawała się w pełni wspierać):
Rozwiązanie pozwala mi zdefiniować obszar tekstowy w następujący sposób:
<textarea class="form-control" [(ngModel)]="this.myModelVariable" appOnlyNumbers [allowNegative]="true" [allowMultiLine]="true" [allowDecimal]="true" [maxLength]="10" placeholder="Enter values (one per line)"></textarea>
Lub jeśli chcę tylko dodatnich liczb całkowitych
<textarea class="form-control" [(ngModel)]="this.myModelVariable" appOnlyNumbers [allowMultiLine]="true" [maxLength]="9" placeholder="Enter values (one per line)"></textarea>
Oto moja dyrektywa:
import { Directive, HostListener, Input, ElementRef } from '@angular/core'; @Directive({ selector: '[appOnlyNumbers]' }) export class OnlyNumbersDirective { constructor(private el: ElementRef) { } @Input() allowMultiLine: boolean = false; @Input() allowNegative: boolean = false; @Input() allowDecimal: boolean = false; @Input() maxLength: number = 0; regex: RegExp; @HostListener('keypress', ['$event']) onKeyPress(event: KeyboardEvent) { this.validate(event, event.key === 'Enter' ? '\n' : event.key); } @HostListener('paste', ['$event']) onPaste(event: Event) { const pastedText = (<any>window).clipboardData && (<any>window).clipboardData.getData('Text') // If IE, use window || <ClipboardEvent>event && (<ClipboardEvent>event).clipboardData.getData('text/plain'); // Non-IE browsers this.validate(event, pastedText); } @HostListener('cut', ['$event']) onCut(event: Event) { this.validate(event, ''); } validate(event: Event, text: string) { const txtInput = this.el.nativeElement; const newValue = (txtInput.value.substring(0, txtInput.selectionStart) + text + txtInput.value.substring(txtInput.selectionEnd)); if (!this.regex) { this.regex = <RegExp>eval('/^' + (this.allowNegative ? '-?' : '') + (this.allowDecimal ? '((\\d+\\.?)|(\\.?))\\d*' : '\\d*') + '$/g'); } var lines = this.allowMultiLine ? newValue.split('\n') : [newValue]; for (let line of lines) { let lineText = line.replace('\r', ''); if (this.maxLength && lineText.length > this.maxLength || !lineText.match(this.regex)) { event.preventDefault(); return; } } } }
źródło
Aby to osiągnąć, powiązałem funkcję z metodą onInput w następujący sposób:
(input)="stripText(infoForm.get('uin'))
Oto przykład w moim formularzu:
<form [formGroup]="infoForm" (submit)="next()" class="ui form"> <input type="text" formControlName="uin" name="uin" id="uin" (input)="stripText(infoForm.get('uin'))" required/> </form>
Następnie dodałem następującą funkcję do mojego komponentu:
stripText(control: FormControl) { control.setValue(control.value.replace(/[^0-9]/g, '')); }
To wyrażenie regularne
/[^0-9]/g
wyszukuje wszystko, co nie jest liczbą i używając.replace
ustawiam go tak, aby był niczym. Więc kiedy użytkownik próbuje wpisać znak, który nie jest liczbą (w tym przypadku znak, który nie jest liczbą od zera do dziewiątki), wygląda to tak, jakby nic się nie działo w polu tekstowym.źródło
Dzięki dla JeanPaul A. i rdanielmurphy. Zrobiłem własną niestandardową dyrektywę, aby ograniczyć pole wejściowe tylko do liczby. Dodano również atrybuty wejściowe max i min. Będzie działać również w kątowej 7.
Kątowy
import { Directive, ElementRef, Input, HostListener } from '@angular/core'; @Directive({ selector: '[appNumberOnly]' }) export class NumberOnlyDirective { // Allow decimal numbers. The \. is only allowed once to occur private regex: RegExp = new RegExp(/^[0-9]+(\.[0-9]*){0,1}$/g); // Allow key codes for special events. Reflect : // Backspace, tab, end, home private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home']; constructor(private el: ElementRef) { } @Input() maxlength: number; @Input() min: number; @Input() max: number; @HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { // Allow Backspace, tab, end, and home keys if (this.specialKeys.indexOf(event.key) !== -1) { return; } // Do not use event.keycode this is deprecated. // See: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode const current: string = this.el.nativeElement.value; // We need this because the current value on the DOM element // is not yet updated with the value from this event const next: string = current.concat(event.key); if (next && !String(next).match(this.regex) || (this.maxlength && next.length > this.maxlength) || (this.min && +next < this.min) || (this.max && +next >= this.max)) { event.preventDefault(); } } @HostListener('paste', ['$event']) onPaste(event) { // Don't allow pasted text that contains non-numerics const pastedText = (event.originalEvent || event).clipboardData.getData('text/plain'); if (pastedText) { const regEx = new RegExp('^[0-9]*$'); if (!regEx.test(pastedText) || (this.maxlength && pastedText.length > this.maxlength) || (this.min && +pastedText < this.min) || (this.max && +pastedText >= this.max)) { event.preventDefault(); } } } }
HTML
<input type="text" class="text-area" [(ngModel)]="itemName" maxlength="3" appNumberOnly />
źródło
Nowoczesne podejście do najlepszej odpowiedzi (bez przestarzałego e.keyCode):
@HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if (['Delete', 'Backspace', 'Tab', 'Escape', 'Enter', 'NumLock', 'ArrowLeft', 'ArrowRight', 'End', 'Home', '.'].indexOf(e.key) !== -1 || // Allow: Ctrl+A (e.key === 'a' && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+C (e.key === 'c' && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+V (e.key === 'v' && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+X (e.key === 'x' && (e.ctrlKey || e.metaKey))) { // let it happen, don't do anything return; } // Ensure that it is a number and stop the keypress if ((e.shiftKey || ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].indexOf(e.key) === -1)) { e.preventDefault(); } }
źródło
Arbitralna dyrektywa RegExp
Oto mała dyrektywa, która używa dowolnego wyrażenia regularnego i blokuje użytkownikowi wpisanie nieprawidłowej wartości
Pokaż fragment kodu
import {Directive, HostListener, Input} from '@angular/core'; @Directive({selector: '[allowedRegExp]'}) export class AllowedRegExpDirective { @Input() allowedRegExp: string; @HostListener('keydown', ['$event']) onKeyDown(event: any) { // case: selected text (by mouse) - replace it let s= event.target.selectionStart; let e= event.target.selectionEnd; let k= event.target.value + event.key; if(s!=e) { k= event.target.value k= k.slice(0,s) + event.key + k.slice(e,k.length); } // case: special characters (ignore) if(['ArrowLeft','ArrowRight','ArrowUp','ArroDown','Backspace','Tab','Alt' 'Shift','Control','Enter','Delete','Meta'].includes(event.key)) return; // case: normal situation - chceck regexp let re = new RegExp(this.allowedRegExp); if(!re.test(k)) event.preventDefault(); } }
Aby zamaskować tylko liczby, użyj
<input [allowedRegExp]="'^[0-9]*$'" type="text" ... >
źródło
Po prostu utwórz dyrektywę i dodaj poniżej hostlistener:
@HostListener('input', ['$event']) onInput(event: Event) { this.elementRef.nativeElement.value = (<HTMLInputElement>event.currentTarget).value.replace(/[^0-9]/g, ''); }
Zastąp nieprawidłowy tekst pustym tekstem. Wszystkie klucze i kombinacje klawiszy będą teraz działać we wszystkich przeglądarkach aż do IE9.
źródło
Wzorzec prawidłowego numeru telefonu komórkowego ('^ ((\ + 91 -?) | 0)? [0-9] {10} $')
Wzorzec akceptacji tylko numeru z wzorca pola tekstowego („[0-9] *”)
wzór akceptacji tylko numeru z określonym numerem, np .: Kod PIN. wzorzec ('^ [0-9] {5} $')
źródło
Dokonałem pewnych modyfikacji w powyższej dyrektywie i zaimplementowałem min, max, maxlength.
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ selector: '[numberOnly]' }) export class NumbersOnlyDirective { private regex: RegExp = new RegExp(/[0-9]/g); // Allow key codes for special events. Reflect : private specialKeys: Array<number> = [46, 8, 9, 27, 13, 110, 190, 35, 36, 37, 39]; // Backspace, tab, end, home @Input() maxlength: number; @Input() min: number; @Input() max: number; constructor(private el: ElementRef) { } @HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { e = <KeyboardEvent>event; if (( (this.specialKeys.indexOf(event.which) > -1) || // to allow backspace, enter, escape, arrows (e.which == 65 && e.ctrlKey == true) || // Allow: Ctrl+C (e.which == 67 && e.ctrlKey == true) || // Allow: Ctrl+X (e.which == 88 && e.ctrlKey == true))) { return; } else if (// to allow numbers (e.which >= 48 && e.which <= 57) || // to allow numpad number (event.which >= 96 && event.which <= 105)) { } else { event.preventDefault(); } let current: string = this.el.nativeElement.value; let next: string = current.concat(event.key); if ((next && !String(next).match(this.regex)) || (this.maxlength && next.length > this.maxlength) || (this.min && +next < this.min) || (this.max && +next >= this.max)) { event.preventDefault(); } } }
źródło
z odpowiedzi @omeralper. Zmienię trochę, żeby nie akceptować okresowego ascii (kod klucza 110,190). i użyj let ch = (e.key); w porównaniu z wyrażeniami regularnymi, gdy zmieniasz język (np. język tajski lub japoński), nie będzie akceptować znaków tego języka
export class OnlyNumber { regexStr = '^[0-9]*$'; constructor(private el: ElementRef) { } @Input() OnlyNumber: boolean; @HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if (this.OnlyNumber) { // console.log(event, this.OnlyNumber); if ([46, 8, 9, 27, 13].indexOf(e.keyCode) !== -1) { return; } let ch = (e.key); let regEx = new RegExp(this.regexStr); if(regEx.test(ch)) return; else e.preventDefault(); } } }
Mam nadzieję, że to pomoże :)
źródło
Możesz utworzyć ten Walidator i zaimportować go do swojego komponentu.
Zasadniczo sprawdza poprawność ciągu wejściowego formularza:
Aby zaimplementować to w swoim projekcie:
importować do swojego komponentu
import { NumberValidator } from '../../validators/number.validator';
inputNumber: ['', [NumberValidator.isInteger]],
(change)="deleteCharIfInvalid()"
z wejściem, jeśliform.get('inputNumber').hasError('isInteger')
taktrue
, usuń ostatni wstawiony znak.// FILE: src/app/validators/number.validator.ts import { FormControl } from '@angular/forms'; export interface ValidationResult { [key: string]: boolean; } export class NumberValidator { public static isInteger(control: FormControl): ValidationResult { // check if string has a dot let hasDot:boolean = control.value.indexOf('.') >= 0 ? true : false; // convert string to number let number:number = Math.floor(control.value); // get result of isInteger() let integer:boolean = Number.isInteger(number); // validate conditions let valid:boolean = !hasDot && integer && number>0; console.log('isInteger > valid', hasDot, number, valid); if (!valid) { return { isInteger: true }; } return null; } }
źródło
Number.isInteger(Math.floor(control.value))
zawsze będzie prawdą? Myślę, że powinno byćparseFloat
zamiast tego.Z obsługą dezynfekcji wklejonej zawartości:
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ selector: '[NumbersOnly]' }) export class NumbersOnlyDirective { DIGITS_REGEXP = new RegExp(/\D/g); constructor(private el: ElementRef) { // Sanatize clipboard by removing any non-numeric input after pasting this.el.nativeElement.onpaste = (e:any) => { e.preventDefault(); let text; let clp = (e.originalEvent || e).clipboardData; if (clp === undefined || clp === null) { text = (<any>window).clipboardData.getData('text') || ''; if (text !== '') { text = text.replace(this.DIGITS_REGEXP, ''); if (window.getSelection) { let newNode = document.createElement('span'); newNode.innerHTML = text; window.getSelection().getRangeAt(0).insertNode(newNode); } else { (<any>window).selection.createRange().pasteHTML(text); } } } else { text = clp.getData('text/plain') || ''; if (text !== '') { text = text.replace(this.DIGITS_REGEXP, ''); document.execCommand('insertText', false, text); } } }; } @HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 || // Allow: Ctrl+A (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+C (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+V (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+X (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) || // Allow: home, end, left, right (e.keyCode >= 35 && e.keyCode <= 39)) { // let it happen, don't do anything return; } // Ensure that it is a number and stop the keypress if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { e.preventDefault(); } } }
źródło
Oto prosta: Dyrektywa prosta W zdarzeniu keydown sprawdza, czy długość klucza wynosi jeden, a klucz nie jest liczbą do
preventDefault()
i nie renderuje tego znaku.import {Directive, ElementRef, HostListener} from '@angular/core'; @Directive({ selector: '[numbersOnly]' }) export class NumbersOnlyDirective { @HostListener('keydown', ['$event']) keyDownEvent(event: KeyboardEvent) { if (event.key.length === 1 && (event.which < 48 || event.which > 57)) { event.preventDefault(); } } }
HTML:
<input type="text" [(ngModel)]="numModel" numbersOnly />
Ograniczenia: Umożliwi to wklejanie za pomocą myszy w ten sposób, aby akceptować inne znaki. Aby tego uniknąć, możesz przekazać model jako dane wejściowe do dyrektywy i
ngOnChage
zmienić wartość modelu tylko na liczby:Jak poniżej:
EDYCJA: Dodano kod, aby wykryć zmianę w modelu i zaktualizować wartość wejścia
import {Directive, ElementRef, HostListener, Input, OnChanges} from '@angular/core'; @Directive({ selector: '[numbersOnly]' }) export class NumbersOnlyDirective implements OnChanges { @Input() numbersOnly: any; constructor(private el: ElementRef) {} @HostListener('keydown', ['$event']) keyDownEvent(event: KeyboardEvent) { // Add other conditions if need to allow ctr+c || ctr+v if (event.key.length === 1 && (event.which < 48 || event.which > 57)) { event.preventDefault(); } } ngOnChanges(changes) { if (changes.numbersOnly) { this.el.nativeElement.value = this.el.nativeElement.value.replace(/[^0-9]/g, ''); } } }
HTML:
<input type="text" [(ngModel)]="numModel" [numbersOnly]="numModel" />
źródło
import {Directive, ElementRef, HostListener, Output, EventEmitter} from '@angular/core'; //only-digits @Directive({ selector: '[only-digits]' }) export class OnlyDigits { constructor(public el: ElementRef) { this.el.nativeElement.onkeypress = (evt) => { if (evt.which < 48 || evt.which > 57) { evt.preventDefault(); } }; } }
Dyrektywa to także najlepszy sposób na zrobienie tego
źródło
Przesyłanie, ponieważ działa również z początkowymi 0, takimi jak 00345
@Directive({ selector: '[appOnlyDigits]' }) export class AppOnlyDigitsDirective { @HostListener('input', ['$event']) onKeyDown(ev: KeyboardEvent) { const input = ev.target as HTMLInputElement; input.value = String(input.value.replace(/\D+/g, '')); } }
źródło
<input oninput="this.value=this.value.replace(/[^0-9]/g,'')"
lub: 2. w pliku HTML:
<input [(ngModel)]="data" (keypress)="stripText($event)" class="form-control">
w pliku ts:
stripText(event) { const seperator = '^([0-9])'; const maskSeperator = new RegExp(seperator , 'g'); let result =maskSeperator.test(event.key); return result; }
To 2 rozwiązanie działa
źródło
fromCharCode zwraca „a” po naciśnięciu klawisza numerycznego „1”, więc należy unikać tej metody
(administrator: nie mógł jak zwykle komentować)
źródło
Widziałem wiele komentarzy dotyczących obsługi kopiowania / wklejania.
Aby wycofać się z odpowiedzi @omeralper, możesz dodać procedurę obsługi zdarzenia wklejania do dyrektywy onlyNumber, aby obsługiwać kopiowanie / wklejanie:
@HostListener('paste', ['$event']) onPaste(event) { // Don't allow pasted text that contains non-numerics var pastedText = (event.originalEvent || event).clipboardData.getData('text/plain'); if (pastedText) { var regEx = new RegExp('^[0-9]*$'); if (!regEx.test(pastedText)) { event.preventDefault(); } }
Umożliwi to kopiowanie i wklejanie treści do pola tekstowego TYLKO wtedy, gdy jest to liczba. To najprostsze rozwiązanie. Zmiana zawartości schowka w celu usunięcia wartości nienumerycznych jest znacznie bardziej skomplikowana i może nie być tego warta.
Aby wkleić tekst z IE, możesz skorzystać z:
window.clipboardData.getData('Text');
źródło
Jeśli używasz primeng i Angular 6 lub nowszego, dostępny jest komponent p-inputMask. Zapobiega wpisywaniu alfabetu ORAZ wartościom ujemnym https://www.primefaces.org/primeng/#/inputmask
źródło
Samo napisanie nie byłoby łatwe
onlyNumbers(event) { if(isNaN(event.target.value * 1)) { console.log("Not a number") } else { console.log("Number") }
}
źródło
Możesz również utworzyć dyrektywę, która implementuje interfejs ControlValueAccessor ( https://angular.io/api/forms/ControlValueAccessor ).
Zobacz przykład roboczy tutaj: https://stackblitz.com/edit/angular-input-field-to-accept-only-numbers
Możesz słuchać zdarzenia „input” i nie ma potrzeby sprawdzania kodów dostępu. Obsługuje kopiowanie i wklejanie oraz ładnie integruje się z API Angular Forms dzięki interfejsowi ControlValueAccessor.
Dyrektywa:
@Directive({ ... selector: '[onlyNumber]' }) export class OnlyNumberDirective implements ControlValueAccessor { private onChange: (val: string) => void; ... private value: string; constructor( private elementRef: ElementRef, private renderer: Renderer2 ) { } ... @HostListener('input', ['$event.target.value']) onInputChange(value: string) { const filteredValue: string = filterValue(value); this.updateTextInput(filteredValue, this.value !== filteredValue); } private updateTextInput(value, propagateChange) { this.renderer.setProperty(this.elementRef.nativeElement, 'value', value); if (propagateChange) { this.onChange(value); } this.value = value; } // ControlValueAccessor Interface ... registerOnChange(fn: any): void { this.onChange = fn; } writeValue(value: string): void { value = value ? String(value) : ''; this.updateTextInput(value, false); } } function filterValue(value): string { return value.replace(/[^0-9]*/g, ''); }
Stosowanie:
<input name="number" type="text" onlyNumber [(ngModel)]="someNumber">
źródło