Angular2 - Eingabefeld zum Akzeptieren nur von Zahlen


86

Wie kann ich in Angular 2 ein Eingabefeld (Textfeld) so maskieren, dass nur Zahlen und keine alphabetischen Zeichen akzeptiert werden?

Ich habe die folgende HTML-Eingabe:

<input 
  type="text" 
  *ngSwitchDefault 
  class="form-control" 
  (change)="onInputChange()" 
  [(ngModel)]="config.Value" 
  (focus)="handleFocus($event)" 
  (blur)="handleBlur($event)"
/>

Die obige Eingabe ist eine generische Texteingabe, die entweder als einfaches Textfeld oder als numerisches Feld verwendet werden kann, um beispielsweise das Jahr anzuzeigen.

Wie kann ich mit Angular 2 dasselbe Eingabesteuerelement verwenden und eine Art Filter / Maske auf dieses Feld anwenden, sodass nur Zahlen akzeptiert werden?

Was sind die verschiedenen Möglichkeiten, wie ich dies erreichen kann?

Hinweis: Ich muss dies nur mit einem Textfeld und nicht mit dem Typ der Eingabenummer erreichen.


1
Könnten Sie nur das HTML-Attribut verwenden? Typ = Nummer
inoabrian

@inoabrian Ich möchte dies erreichen, ohne den Nummerntyp zu verwenden.
Aniruddha Pondhe

Antworten:


112

Sie können angle2-Direktiven verwenden. 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();
        }
      }
  }
}

und Sie müssen den Direktivennamen in Ihre Eingabe als Attribut schreiben

<input OnlyNumber="true" />

Vergessen Sie nicht, Ihre Direktive in das Deklarationsarray Ihres Moduls zu schreiben.

Bei Verwendung von Regex benötigen Sie weiterhin Funktionstasten

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

1
Das ist großartig. Wie kann ich mit RegEx-Mustern dasselbe erreichen?
Aniruddha Pondhe

3
Kopieren und Einfügen ist nicht möglich.
Shardul

@ Hardul nur (e.keyCode == 86 && e.ctrlKey === true)zu Bedingungen hinzufügen , Kopie funktioniert, aber Einfügen funktionierte nicht
Al-Mothafar

1
Wie füge ich Leerzeichen plus und minus hinzu?
Zahidul Islam Ruhel


65

Wenn Sie keine Richtlinie wollen

https://stackblitz.com/edit/numeric-only

in component.html

<input (keypress)="numberOnly($event)" type="text">

in 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;

  }
}

33
Das Problem bei diesem Ansatz besteht darin, dass Schlüsselereignisse nicht das Einfügen eines Benutzers oder das automatische Ausfüllen des Eingabefelds durch einen Browser erfassen. Das ist also eine schlechte Lösung.
Darryn Hosking

30

Ich weiß, dass dies eine alte Frage ist, aber da dies eine übliche Funktion ist, möchte ich die von mir vorgenommenen Änderungen mitteilen:

  • Benutzerdefiniertes Dezimaltrennzeichen (Punkt oder Komma)
  • Unterstützung nur für Ganzzahlen oder Ganzzahlen und Dezimalstellen
  • Unterstützung nur für positive Zahlen oder positive und negative
  • Das Minuszeichen (-) bestätigen steht am Anfang
  • Unterstützung für das Einfügen von Mäusen (mit einigen Einschränkungen durch https://caniuse.com/#feat=clipboard )
  • Unterstützung für Mac-Befehlstaste
  • Ersetzen Sie Zeichenfolgen wie ".33" und "33". für die richtigen Versionen: 0.33 und 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);
                }
            }
        }
    }
    

Verwendung:

 <input NumbersOnly
        [allowDecimals]="true"
        [allowSign]="true"
        type="text">

Ich habe die letzte Zeile der validatevalue-Methode geändert, um zu verhindern, dass für ungültiges Einfügen eine Null hinzugefügt wird. if (valid) {this.hostElement.nativeElement ['value'] = value;}
Abdul Rehman sagte

Können Sie bitte auch eine Drag & Drop-Validierung hinzufügen? Außerdem habe ich festgestellt, dass sich der Wert der Eingabefelder in den mit 0 aufgefüllten Wert für das führende und nachfolgende Dezimaltrennzeichen ändert, der Wert jedoch nicht in der Zwei-Wege-Bindungsvariablen aktualisiert wird. Beispiel: [(NgModel)] = "myVariable". Wenn wir hier .3 in das Eingabefeld eingeben, ändert sich der Wert in der Texteingabe bei Unschärfe auf 0,3, aber der Wert in myVariable bleibt weiterhin '.3'.
Sushmit Sagar

Eingabe zum Löschen und Eingeben fehlt, aber die Lösung ist trotzdem sehr gut
Oleg Bondarenko

29

Ich möchte auf der Antwort von @omeralper aufbauen, die meiner Meinung nach eine gute Grundlage für eine solide Lösung bot.

Was ich vorschlage, ist eine vereinfachte und aktuelle Version mit den neuesten Webstandards. Es ist wichtig zu beachten, dass event.keycode aus den Webstandards entfernt wird und zukünftige Browser-Updates dies möglicherweise nicht mehr unterstützen. Siehe https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode

Weiterhin ist die Methode

String.fromCharCode(e.keyCode);

garantiert nicht, dass der keyCode, der sich auf die vom Benutzer gedrückte Taste bezieht, dem erwarteten Buchstaben entspricht, der auf der Tastatur des Benutzers angegeben ist, da unterschiedliche Tastaturkonfigurationen dazu führen, dass ein bestimmter Keycode unterschiedliche Zeichen enthält. Wenn Sie dies verwenden, treten Fehler auf, die schwer zu identifizieren sind und die Funktionalität für bestimmte Benutzer leicht beeinträchtigen können. Ich schlage eher die Verwendung von event.key vor, siehe Dokumente hier https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Außerdem möchten wir nur, dass die resultierende Ausgabe eine gültige Dezimalzahl ist. Dies bedeutet, dass die Nummern 1, 11.2, 5000.2341234 akzeptiert werden sollten, der Wert 1.1.2 jedoch nicht akzeptiert werden sollte.

Beachten Sie, dass ich in meiner Lösung die Funktionen zum Ausschneiden, Kopieren und Einfügen ausschließe, da Fenster für Fehler geöffnet werden, insbesondere wenn unerwünschte Texte in zugehörige Felder eingefügt werden. Dies würde einen Bereinigungsprozess für einen Keyup-Handler erfordern. Das ist nicht der Umfang dieses Threads.

Hier ist die Lösung, die ich vorschlage.

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

Dies ist ein wirklich interessanter Ansatz. Haben Sie Vorschläge zur Implementierung der Funktion zum Kopieren / Einfügen, ohne auf ältere Methoden wie (e.keyCode == 67 && e.ctrlKey === true) zurückzugreifen?
Ender2050

1
Ich habe dies nicht persönlich versucht, aber Sie können auch die ausgelösten Copy / Paste-Ereignisse anhören. Sie generieren ein ClipboardEvent ( developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent ), das die Daten enthält, die kopiert / eingefügt werden. Der einzige Nachteil ist, dass dies noch experimentell ist und nur von den neuesten Browsern unterstützt wird - caniuse.com/#search=paste
JeanPaul A.

Ich habe einen ähnlichen Ansatz versucht, aber leider funktioniert dies nicht in jedem Fall. Ihre "nächste" Variable geht davon aus, dass das gedrückte Zeichen am Ende des aktuell eingegebenen Werts steht. Dies ist nicht immer der Fall. Zum Beispiel, wenn jemand 100 eingibt und dann beschließt, 1100 zu machen, indem eine 1 an die Vorderseite angehängt wird. Ihre "nächste" Variable ist falsch (1001).
Carlos Rodriguez

Da der 'nächste' Wert nur verwendet wird, um zu überprüfen, ob der eingegebene Betrag eine gültige Dezimalzahl ist (und um den Wert nicht festzulegen), würde das Anhängen am Ende die Regex-Validierung nicht ändern.
JeanPaul A.

Nur ich möchte diese Zeile hinzufügen, um sie in der Eingabesteuerung anzuwenden. <Eingabe myNumberOnly type = "text" id = "yourId">
Lrodriguez84

17

Eine präzisere Lösung. Versuchen Sie diese Anweisung.

Kann auch verwendet werden, wenn Sie ReactiveForms verwenden.

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

Verwenden Sie es für Ihre Eingaben wie folgt:

<input matInput formControlName="aNumberField" numberOnly>

1
Während diese Lösung funktioniert, werden Modelländerungsereignisse
Dies

Zu Ntziolis 'Kommentar: Bisher funktioniert die Lösung von Ben Gulapa für mich. Die von ntziolis genannte Lösung ist dies jedoch nicht. Verzeihen Sie mir, wenn ich falsch liege, aber es scheint, dass das Problem mit dem Code unter dem obigen Link zu stackblitz, zumindest für mich, darin bestand, dass das letzte unerwünschte Zeichen, das ich eingegeben habe, obwohl es nie in der Benutzeroberfläche angezeigt wurde, irgendwie aufgetreten ist in die gebundene Variable meiner Komponente setzen. Nur der letzte unerwünschte Charakter.
user2367418

So fahren Sie mit meinem Kommentar fort: Verwenden von Angular 7 und eines auf zwei Zeichen beschränkten HMTL-Eingabetextes.
user2367418

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

14

Sie müssen stattdessen type = "number" als Text verwenden. Sie können auch maximale und minimale Zahlen angeben

<input type="number" name="quantity" min="1" max="5">

2
Ich möchte dies erreichen, ohne den Nummerntyp zu verwenden.
Aniruddha Pondhe

3
Die Unterstützung für den Nummerntyp ist immer noch ziemlich fehlerhaft,
Nicolas Forney

9
Der Nachteil von type="number"ist, dass es Charakter eals Teil der wissenschaftlichen Notation akzeptiert
user776686

12

Sie können es so erreichen

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

hoffe das wird dir helfen.


Könnten Sie das näher erläutern? Was macht event.charCode == 8?
Bosari

9

Sie könnten Regex verwenden:

<input type="text" (keypress)="numericOnly($event)">

numericOnly(event): boolean {    
    let patt = /^([0-9])$/;
    let result = patt.test(event.key);
    return result;
}

1
Ja, es ist hilfreich, aber ich möchte (.) Dezimal auch in meinem Eingabefeld
Rinku Choudhary

6

Verwenden Sie das patternAttribut für die Eingabe wie folgt:

<input type="text" pattern="[0-9]+" >

es funktioniert nicht. Wenn Sie mit der
Eingabe

6

Ich weiß, dass dies viele Antworten hat, aber ich musste Folgendes behandeln (was keine der Antworten vollständig zu unterstützen schien):

  • Unterstützung des Textbereichs mit Option für mehrzeilige
  • Dezimalstellen oder negative Zahlen
  • Maximale Länge pro Zeile
  • Browserübergreifende Unterstützung (Chrome, Edge, IE 11)
  • Behandeln von Ausschneide- / Einfügevorgängen und -ereignissen

Die Lösung ermöglicht es mir, einen Textbereich wie diesen zu definieren:

<textarea class="form-control" [(ngModel)]="this.myModelVariable"
    appOnlyNumbers [allowNegative]="true" [allowMultiLine]="true" 
    [allowDecimal]="true" [maxLength]="10"
    placeholder="Enter values (one per line)"></textarea>

Oder wenn ich nur positive ganze Zahlen will

<textarea class="form-control" [(ngModel)]="this.myModelVariable"
    appOnlyNumbers [allowMultiLine]="true" [maxLength]="9"
    placeholder="Enter values (one per line)"></textarea>

Hier ist meine Anweisung:

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

}

4

Um dies zu erreichen, habe ich eine Funktion wie folgt an die onInput-Methode gebunden:

(input)="stripText(infoForm.get('uin'))

Hier ist das Beispiel in meinem Formular:

<form [formGroup]="infoForm" (submit)="next()" class="ui form">
    <input type="text" formControlName="uin" name="uin" id="uin" (input)="stripText(infoForm.get('uin'))" required/>
</form>

Dann habe ich meiner Komponente die folgende Funktion hinzugefügt:

  stripText(control: FormControl) {
   control.setValue(control.value.replace(/[^0-9]/g, ''));
  }

Diese Regex /[^0-9]/gsucht nach etwas, das keine Zahl ist, und mit .replaceI setze ich, dass es durch nichts ersetzt wird. Wenn ein Benutzer versucht, ein Zeichen einzugeben, das keine Zahl ist (in diesem Fall ein Zeichen, das nicht null bis neun ist), sieht es so aus, als ob im Textfeld nichts passiert.


4

Vielen Dank an JeanPaul A. und rdanielmurphy. Ich hatte meine eigene benutzerdefinierte Anweisung erstellt, um das Eingabefeld nur auf die Anzahl zu beschränken. Außerdem wurden die Eingabeattribute max und min hinzugefügt. Funktioniert auch in Winkel 7.

Winkelig

    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 />

4

Ein moderner Ansatz für die beste Antwort (ohne veralteten 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();
    }
}

1
Das ist fantastisch! @Directive ({Selektor: "[inputNumericInput]"}) Exportklasse NumericInputDirective {@HostListener ()}
Nate

1
Funktioniert gut. Nur beim Kopieren und Einfügen beobachtete Nebenwirkung. Es ermöglicht das Kopieren und Einfügen externer nicht numerischer Zeichenfolgen. Googelte und fand eine bessere Lösung, die diese @ stackblitz.com/edit/…
vinsinraw

4

Beliebige RegExp-Direktive

Hier ist eine kleine Direktive, die einen beliebigen regulären Ausdruck verwendet und den Benutzer blockiert, um einen ungültigen Wert einzugeben

Um nur Zahlen zu maskieren, verwenden Sie

<input [allowedRegExp]="'^[0-9]*$'" type="text" ... >

Leider können Sie diese Lösung austricksen, indem Sie Circumflex + was auch immer Sie schreiben möchten, spammen.
ProgFroz

3

Erstellen Sie einfach eine Direktive und fügen Sie unten den Hostlistener hinzu:

@HostListener('input', ['$event'])
    onInput(event: Event) {
        this.elementRef.nativeElement.value = (<HTMLInputElement>event.currentTarget).value.replace(/[^0-9]/g, '');
    }

Ersetzen Sie ungültigen Text durch leeren. Alle Schlüssel und Tastenkombinationen funktionieren jetzt in allen Browsern bis IE9.


Wenn Sie mit char beginnen, wird char nicht angehängt, aber die Anzahl der Modelllängen beträgt 1. Wie kann man das lösen?. Auch wenn das Element eine maximale Länge hat und dann gemischten Inhalt kopiert und einfügt, entspricht die Modellanzahl der maximalen Länge. Zum Beispiel hat die maximale Länge 10, dann kopiert und fügt 1238261jhgjh12987 zur Eingabe nur 123816 an, aber die Länge des Modells würde 10 dauern. Irgendwelche Lösungen?
Satheesh Natarajan

3

Muster für das gültige Handynummernmuster ('^ ((\ + 91 -?) | 0)? [0-9] {10} $')

Muster zum Akzeptieren nur der Nummer aus dem Textfeldmuster ('[0-9] *')

Muster, um nur eine Nummer mit einer bestimmten Nummer zu akzeptieren, z. B.: Pincode. Muster ('^ [0-9] {5} $')


2

Ich habe einige Änderungen an der obigen Richtlinie vorgenommen und min, max, maxlength implementiert.

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

  }
}

wie man den maximalen Längenwert aus dem Eingabefeld angibt
Jason Brody

<input id = "COMN" class = "wb-e-inp-1__input" type = "text" appNumberOnly maxlength = "10" /> funktioniert
Jason Brody

1

aus der Antwort von @omeralper. Ich ändere ein wenig, das Punkt ASCII nicht akzeptiert (Schlüsselcode 110,190). und benutze let ch = (e.key); Wenn Sie die Sprache ändern (z. B. Thai oder Japanisch), wird der Charakter dieser Sprache nicht akzeptiert

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

Ich hoffe das hilft :)


1

Sie können diesen Validator erstellen und in Ihre Komponente importieren.
Überprüft grundsätzlich die Formulareingabezeichenfolge:

  • Überprüfen Sie, ob kein Punkt vorhanden ist
  • konvertiert String in Zahl
  • check ist eine ganze Zahl
  • Prüfung ist größer als Null

So implementieren Sie es in Ihrem Projekt:

  1. Vorgeschlagener Pfad in Ihrem App-Ordner: src / app / validators / number.validator.ts
  2. in Ihre Komponente importieren

    import { NumberValidator } from '../../validators/number.validator';

  3. Fügen Sie es dem Formularsteuerelement hinzu
    inputNumber: ['', [NumberValidator.isInteger]],
  4. Wenn Sie das ungültige Zeichen nicht anzeigen möchten, binden Sie a (change)="deleteCharIfInvalid()"an die Eingabe. Wenn dies der Fall form.get('inputNumber').hasError('isInteger')ist true, löschen Sie das zuletzt eingefügte Zeichen.
// 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;
    }        
}

Wird nicht Number.isInteger(Math.floor(control.value))immer wahr sein? Ich denke es sollte parseFloatstattdessen sein.
AndyTheEntity

1

Mit Unterstützung für die Bereinigung eingefügter Inhalte:

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

}

1

Hier ist eine einfache Anweisung: Einfache Anweisung Bei einem Keydown-Ereignis wird überprüft, ob die Länge eines Schlüssels eins ist und der Schlüssel keine Zahl ist, preventDefault()und dieses Zeichen wird nicht gerendert.

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 />

Einschränkungen: Auf diese Weise können Sie mit einer Maus andere Zeichen einfügen. Um dies zu vermeiden, können Sie das Modell als Eingabe an die Direktive übergeben und ngOnChagean dieses Modell den Wert nur in Zahlen ändern:

Wie unten:

BEARBEITEN: Code hinzugefügt, um Änderungen im Modell zu erkennen und den Wert der Eingabe zu aktualisieren

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" />

Wenn Sie mit char beginnen, wird char nicht angehängt, aber die Anzahl der Modelllängen beträgt 1. Wie kann man das lösen?
Satheesh Natarajan

Wenn Sie nach der Länge suchen, bleibt sie in der Direktive vor und nach dem Vornehmen von Änderungen 0. Wenn es irgendwann eins ist, sollte es schnell wieder auf 0 zurückkehren.
Lahar Shah

Nein, ist es nicht. Versuchen Sie einfach, numModel.length in Vorlage zu binden und überprüfen Sie die Länge
Satheesh Natarajan

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

      }
    }

Richtlinie ist auch der beste Weg, dies zu tun


1

Casting, weil es auch mit führenden 0 wie 00345 funktioniert

@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, ''));
  }
}

1
  1. <input oninput="this.value=this.value.replace(/[^0-9]/g,'')"

oder: 2. in der HTML-Datei:

 <input [(ngModel)]="data" (keypress)="stripText($event)"
     class="form-control">

in der ts-Datei:

stripText(event) {
const seperator  = '^([0-9])';
const maskSeperator =  new RegExp(seperator , 'g');  
let result =maskSeperator.test(event.key);   return result;   }

Diese 2 Lösung funktioniert


Bitte verwenden Sie Codeblöcke, um Ihre Codefragmente zu formatieren.
YuS

0

fromCharCode gibt beim Drücken des Nummernblocks '1' 'a' zurück, daher sollte dieses Methoid vermieden werden

(admin: konnte nicht wie gewohnt kommentieren)


0

Ich habe viele Kommentare zum Umgang mit Kopieren / Einfügen gesehen.

Um die Antwort von @omeralper zu deaktivieren, können Sie der onlyNumber-Direktive einen Paste-Ereignishandler hinzufügen, um das Kopieren / Einfügen zu handhaben:

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

Dadurch können Inhalte nur dann kopiert und in das Textfeld eingefügt werden, wenn es sich um eine Zahl handelt. Das ist die einfachste Lösung. Das Ändern des Inhalts der Zwischenablage zum Entfernen von nicht numerischen Elementen ist viel komplizierter und möglicherweise nicht sinnvoll.

Um eingefügten Text aus dem IE zu erhalten, können Sie Folgendes verwenden:

window.clipboardData.getData('Text');


0

Wäre nicht einfach genug, nur zu schreiben

onlyNumbers(event) {
if(isNaN(event.target.value * 1)) {
 console.log("Not a number")
} else {
  console.log("Number")
}

}}


0

Sie können auch eine Direktive erstellen, die die ControlValueAccessor-Schnittstelle implementiert ( https://angular.io/api/forms/ControlValueAccessor ).

Siehe Arbeitsbeispiel hier: https://stackblitz.com/edit/angular-input-field-to-accept-only-numbers

Sie können das Eingabeereignis abhören und müssen nicht nach Schlüsselcodes suchen. Es unterstützt das Kopieren und Einfügen und lässt sich dank der ControlValueAccessor-Schnittstelle gut in die Angular Forms-API integrieren.

Richtlinie:

@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, '');
}

Verwendung:

<input name="number" type="text" onlyNumber [(ngModel)]="someNumber">
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.