Angular2 - Yalnızca Sayıları Kabul Etmek İçin Giriş Alanı


87

Angular 2'de, bir girdi alanını (metin kutusu) alfabetik karakterleri değil sadece sayıları kabul edecek şekilde nasıl maskeleyebilirim?

Aşağıdaki HTML girdisine sahibim:

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

Yukarıdaki girdi, basit bir metin alanı olarak veya örneğin yılı göstermek için sayısal bir alan olarak kullanılabilen genel bir metin girdisidir.

Angular 2'yi kullanarak, aynı giriş kontrolünü nasıl kullanabilirim ve bu alana yalnızca sayıları kabul edecek şekilde bir tür filtre / maske uygulayabilirim?

Bunu başarmanın farklı yolları nelerdir?

Not: Bunu yalnızca metin kutusu kullanarak ve giriş sayı türü kullanmadan elde etmem gerekiyor.


1
Sadece html özelliğini kullanabilir misiniz? tür = sayı
inoabrian

@inoabrian Bunu sayı türünü kullanmadan başarmak istiyorum.
Aniruddha Pondhe

Bu size yardımcı olabilir: stackoverflow.com/questions/39799436/…
chandan7

Yanıtlar:


112

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

ve yönerge adını girişinize öznitelik olarak yazmanız gerekir

<input OnlyNumber="true" />

yönergenizi modülünüzün bildirimler dizisine yazmayı unutmayın.

Normal ifadeyi kullanarak işlevsel tuşlara hala ihtiyacınız olacak

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
Bu harika. RegEx kalıplarını kullanarak aynı şeyi başarabilmemin bir yolu var mı?
Aniruddha Pondhe

3
Kopyalayıp yapıştırmaya izin vermez.
Shardul

@Shardul sadece (e.keyCode == 86 && e.ctrlKey === true)koşulları ekleyin , kopyalama çalışıyor ama yapıştırma çalışmıyor
Al-Mothafar

1
Nasıl boşluk, artı ve eksi eklerim?
Zahidul Islam Ruhel


65

Direktif istemiyorsan

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

component.html'de

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

component.ts içinde

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;

  }
}

34
Bu yaklaşımla ilgili sorun, temel olayların bir kullanıcıyı yapıştırmasını veya giriş alanını otomatik olarak dolduran bir tarayıcının yakalamamasıdır. Yani bu kötü bir çözüm.
Darryn Hosking

30

Bunun eski bir soru olduğunu biliyorum, ancak bu yaygın bir işlevsellik olduğundan, yaptığım değişiklikleri paylaşmak istiyorum:

  • Özel ondalık ayırıcı (nokta veya virgül)
  • Yalnızca tam sayı veya tam sayı ve ondalık sayılar için destek
  • Yalnızca pozitif sayılar veya pozitifler ve negatifler için destek
  • Doğrulama eksi işareti (-) başlangıçta
  • Fare yapıştırma desteği (biraz sınırlama olsa da https://caniuse.com/#feat=clipboard )
  • Mac komut tuşu desteği
  • ".33" ve "33" gibi dizeleri değiştirin. doğru sürümler için: 0.33 ve 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);
                }
            }
        }
    }
    

Kullanım:

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

Geçersiz yapıştırma için sıfır eklemeyi önlemek için doğrulama değerinin son satırını değiştirdim. if (geçerli) {this.hostElement.nativeElement ['değer'] = değer;}
Abdul Rehman

lütfen sürükle ve bırak doğrulaması da ekleyebilir misiniz? Ayrıca, giriş alanları değerinin önde gelen ve sondaki ondalık ayırıcı için 0 dolgulu değer olarak değiştiğini ancak değerin iki yönlü bağlama değişkeninde güncellenmediğini fark ettim. örneğin: [(NgModel)] = "myVariable", burada, giriş alanına .3 yazarsak, metin girişindeki değer bulanıklıkta 0.3'e değişir, ancak myVariable'daki değer hala '.3' olarak kalır.
Sushmit Sagar

Sil ve Gir girişi eksik, ancak yine de çözüm çok iyi
Oleg Bondarenko

29

@Omeralper tarafından verilen cevaba dayanarak, bence sağlam bir çözüm için iyi bir temel sağladı.

Önerdiğim şey, en son web standartlarına sahip basitleştirilmiş ve güncel bir sürüm. Event.keycode'un web standartlarından kaldırıldığını ve gelecekteki tarayıcı güncellemelerinin artık desteklemeyebileceğini unutmamak önemlidir. Bkz. Https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode

Ayrıca yöntem

String.fromCharCode(e.keyCode);

farklı klavye konfigürasyonları belirli bir tuş kodu farklı karakterlerle sonuçlanacağından, kullanıcı tarafından basılan tuşa ait keyCode'un, kullanıcının klavyesinde tanımlanan beklenen harf ile eşleşeceğini garanti etmez. Bunu kullanmak, tanımlanması zor olan hatalar ortaya çıkarır ve belirli kullanıcılar için işlevselliği kolayca bozabilir. Bunun yerine, event.key kullanımını öneriyorum, buradaki belgelere bakın https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Dahası, elde edilen çıktının sadece geçerli bir ondalık olmasını istiyoruz. Bu, 1, 11.2, 5000.2341234 sayılarının kabul edilmesi gerektiği ancak 1.1.2 değerinin kabul edilmemesi gerektiği anlamına gelir.

Çözümümde, özellikle insanlar ilişkili alanlara istenmeyen metinler yapıştırdıklarında, hatalar için pencereler açtığı için kes, kopyala ve yapıştır işlevini hariç tuttuğumu unutmayın. Bu, bir anahtarlama işleyicisinde bir temizleme işlemi gerektirirdi; bu iş parçacığının kapsamı değil.

İşte önerdiğim çözüm.

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

Bu gerçekten ilginç bir yaklaşım. (E.keyCode == 67 && e.ctrlKey === true) gibi eski yöntemlere başvurmadan kopyala / yapıştır işlevinin nasıl uygulanacağı konusunda herhangi bir öneriniz var mı?
Ender2050

1
Bunu şahsen denemedim, ancak tetiklenen kopyala / yapıştır olaylarını benzer şekilde dinleyebilirsiniz. Kopyalanan / yapıştırılan verileri içeren bir ClipboardEvent ( developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent ) oluştururlar. Tek dezavantajı, bunun hala deneysel olması ve yalnızca en yeni tarayıcılar tarafından desteklenmesidir - caniuse.com/#search=paste
JeanPaul A.

Benzer bir yaklaşım denedim ama maalesef bu her durumda işe yaramıyor. "Sonraki" değişkeniniz, basılan karakterin o anda yazılan değerin sonuna gittiğini varsayar. Bu her zaman böyle değildir. Örneğin, biri 100 yazarsa ve ardından öne 1 ekleyerek 1100 yapmaya karar verirse. "Sonraki" değişkeniniz yanlış olacaktır (1001).
Carlos Rodriguez

'Sonraki' değer yalnızca giriş miktarının geçerli bir ondalık olup olmadığını kontrol etmek için kullanıldığından (ve değeri ayarlamak için değil), sonuna eklemek normal ifade doğrulamasını değiştirmez.
JeanPaul A.

Sadece bu satırı girdi kontrolüne eklemek istiyorum. <input myNumberOnly type = "text" id = "yourId">
Lrodriguez84

17

Daha özlü bir çözüm. Bu yönergeyi deneyin.

ReactiveForms kullanıyorsanız da kullanılabilir.

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

Bunu girdilerinizde şu şekilde kullanın:

<input matInput formControlName="aNumberField" numberOnly>

1
Bu çözüm işe yarasa da, model değişikliği olaylarını iki kez tetikler, bu, normal ifadeyi
ntziolis

Ntziolis'in yorumuna: Şimdiye kadar Ben Gulapa'nın çözümü benim için çalışıyor. Ancak ntziolis'in atıfta bulunduğu çözüm değil. Yanılıyorsam affedin, ama görünen o ki, yukarıdaki stackblitz bağlantısındaki kodla ilgili sorun, en azından benim için, yazdığım son istenmeyen karakterdi, kullanıcı arayüzünde hiç görünmese de, bir şekilde bileşenimin bağlı değişkenine koyun. Sadece son istenmeyen karakter.
user2367418

Yorumuma devam etmek için: Angular 7 ve bir HMTL girdi metni kullanmak iki karakterle sınırlı.
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

Metin yerine type = "number" kullanmanız gerekir. Maksimum ve minimum sayıları da belirtebilirsiniz

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

2
Bunu numara türünü kullanmadan başarmak istiyorum.
Aniruddha Pondhe

3
Numara türü desteği, bu yanıtta açıklandığı gibi hala oldukça sorunlu: stackoverflow.com/a/14995890/1156185
Nicolas Forney

9
Olumsuz yanı type="number", karakteri ebilimsel gösterimin bir parçası olarak kabul
etmesidir

12

bu şekilde başarabilirsin

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

Umarım bu sana yardımcı olur.


Bu konuda ayrıntılı misiniz? event.charCode == 8 ne yapıyor?
bosari

10

Normal ifadeyi kullanabilirsiniz:

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

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

1
evet yararlı ama ben de ondalık istiyorum (.) giriş
alanımda


6

Bunun birçok cevabı olduğunu biliyorum, ancak aşağıdakileri halletmem gerekiyordu (cevapların hiçbiri tam olarak desteklemiyordu):

  • Çok hatlı seçenekli metin alanı desteği
  • Ondalık sayılar veya negatif sayılar
  • Satır başına maksimum uzunluk
  • Çapraz tarayıcı desteği (Chrome, Edge, IE 11)
  • Kes / yapıştır işlemlerini ve olaylarını işleme

Çözüm, şöyle bir metin alanı tanımlamama izin veriyor:

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

Ya da sadece pozitif tamsayılar istiyorsam

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

İşte benim direktifim:

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

Bunu başarmak için onInput yöntemine bir işlevi şu şekilde bağladım:

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

İşte formumun içindeki örnek:

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

Sonra bileşenime aşağıdaki işlevi ekledim:

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

Bu normal /[^0-9]/gifade, sayı olmayan herhangi bir şeyi arar ve .replaceben kullanarak onu hiçbir şeyle değiştirilecek şekilde ayarlamaz. Dolayısıyla, bir kullanıcı sayı olmayan bir karakteri yazmaya çalıştığında (bu durumda sıfırdan dokuza kadar olmayan bir karakter), metin kutusunda hiçbir şey olmamış gibi görünür.


4

JeanPaul A. ve rdanielmurphy'ye çok teşekkürler. Giriş alanını yalnızca sayı ile sınırlamak için kendi Özel yönergemi oluşturmuştum. Ayrıca max ve min input nitelikleri eklendi. Açısal 7'de de çalışacaktır.

Açısal

    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

En iyi yanıt için modern bir yaklaşım (kullanımdan kaldırılmış e.keyCode olmadan):

@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
Bu harika! @Directive ({selector: "[inputNumericInput]"}) dışa aktarma sınıfı NumericInputDirective {@HostListener ()}
Nate

2
İyi çalışıyor. Kopyalama yapıştırmada sadece yan etki gözlendi. Harici sayısal olmayan dizelerin kopyalanmasını sağlar. Googled ve bunu ele alan daha iyi bir çözüm buldu @ stackblitz.com/edit/…
vinsinraw

4

Keyfi RegExp direktifi

Burada rasgele regexp kullanan ve kullanıcının geçersiz değer yazmasını engelleyen küçük bir yönerge

Yalnızca sayıları maskelemek için şunu kullanın:

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

Ne yazık ki, yazmak istediğiniz her şeyi sirkumflex + spam göndererek bu çözümü kandırabilirsiniz.
ProgFroz

3

Sadece bir yönerge oluşturun ve aşağıdaki hostlistener ekleyin:

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

Geçersiz metni boş ile değiştirin. Tüm tuşlar ve tuş kombinasyonları artık IE9'a kadar tüm tarayıcılarda çalışacak.


Char ile yazı tipine başlanırsa, char eklenmez ancak model uzunluğunun sayısı 1. Bunu nasıl çözebilirim ?. Ayrıca, elemanın maksimum uzunluğu varsa, karışık içeriği kopyalayıp yapıştırın, model sayısı maksimum uzunluk olacaktır. Örneğin, maksimum uzunluk 10'dur, sonra 1238261jhgjh12987'yi kopyalayıp girişe yapıştırarak yalnızca 123816'yı ekleyecektir ancak modelin uzunluğu 10'dur.
Satheesh Natarajan

3

Geçerli Cep telefonu numarası kalıbı için kalıp ('^ ((\ + 91 -?) | 0)? [0-9] {10} $')

Metin kutusu modelinden yalnızca sayıyı kabul etme kalıbı ('[0-9] *')

sadece belirli bir numarayı kabul etmek için pıtırtı, örneğin: Pin kodu. desen ('^ [0-9] {5} $')


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

veya: 2. HTML Dosyasında:

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

ts Dosyasında:

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

Bu 2 çözüm işe yarıyor


Lütfen kod parçacıklarınızı biçimlendirmek için kod bloklarını kullanın.
YuS

2

Yukarıdaki yönergede bazı değişiklikler yaptım ve min, max, maxlength uyguladım.

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

  }
}

giriş alanından maksimum uzunluk değeri nasıl verilir
Jason Brody

<input id = "COMN" class = "wb-e-inp-1__input" type = "text" appNumberOnly maxlength = "10" /> çalışıyor
Jason Brody

2

00345 gibi önde gelen 0 ile de çalıştığı için döküm

@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

@omeralper'ın cevabından. Ascii dönemini kabul etmeyecek şekilde biraz değiştiriyorum (anahtar kodu 110,190). let ch = (e.key); normal ifadeyle karşılaştırmak için dili değiştirdiğinizde (Tay dili veya Japonca gibi) bu dilin karakterini kabul etmez

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

umarım bu yardımcı olur :)


1

Bu Doğrulayıcıyı oluşturabilir ve bileşeninize aktarabilirsiniz.
Temel olarak form giriş dizesini doğrular:

  • nokta olmadığını kontrol edin
  • dizeyi sayıya dönüştürür
  • kontrol bir tam sayıdır
  • kontrol sıfırdan büyük

Bunu projenize uygulamak için:

  1. uygulama klasörünüzde önerilen yol: src / app / validators / number.validator.ts
  2. bileşeninize aktarın

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

  3. form denetimine ekle
    inputNumber: ['', [NumberValidator.isInteger]],
  4. geçersiz karakteri göstermek istemiyorsanız (change)="deleteCharIfInvalid()", girişe a'yı bağlayın , eğer öyleyse form.get('inputNumber').hasError('isInteger'), trueeklenen son karakteri silin.
// 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;
    }        
}

Her Number.isInteger(Math.floor(control.value))zaman doğru olmayacak mı? Onun parseFloatyerine olması gerektiğini düşünüyorum .
AndyTheEntity

1

Yapıştırılan içeriğin sterilize edilmesi desteği ile:

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

İşte kolay olanı: Basit yönerge Keydown olayında, bir anahtarın uzunluğunun bir olduğunu ve anahtarın bir sayı olmadığını kontrol eder preventDefault()ve bu karakteri oluşturmaz.

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

Sınırlamalar: Diğer karakterleri kabul edecek şekilde bir fare kullanarak yapıştırmaya izin verecektir. Modeli direktifin girdisi olarak aktarabilir ve ngOnChagebu modele değeri yalnızca sayılarla değiştirebilirsiniz:

Aşağıdaki gibi:

DÜZENLE: Modeldeki değişikliği algılamak ve giriş değerini güncellemek için Kod eklendi

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

Char ile yazı tipine başlanırsa, char eklenmez ancak model uzunluğunun sayılması 1 sürer.
Satheesh Natarajan

uzunluğu kontrol ettiğinizde, değişiklik yapmadan önce ve sonra direktifte 0 olarak kalır. Bir noktada bir ise, hızla 0'a dönmelidir.
Lahar Shah

Hayır değil. Sadece şablonda numModel.length bağlamak için denemek ve uzunluk sayısını kontrol
Satheesh Natarajon

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

      }
    }

Direktif aynı zamanda bunu yapmanın en iyi yoludur


0

fromCharCode, '1' sayısal tuş takımına basıldığında 'a' döndürür, bu nedenle bu yöntemden kaçınılmalıdır

(yönetici: her zamanki gibi yorum yapamadı)


0

Kopyalama / yapıştırma işlemleriyle ilgili birçok yorum gördüm.

@Omeralper yanıtını geri almak için, kopyalama / yapıştırmayı işlemek için onlyNumber direktifine bir paste olay işleyicisi ekleyebilirsiniz:

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

Bu, içeriğin YALNIZCA bir sayı olması durumunda metin kutusuna kopyalanıp yapıştırılmasına izin verecektir. En basit çözüm budur. Pano içeriğini sayısal olmayanları kaldırmak için değiştirmek çok daha karmaşıktır ve buna değmeyebilir.

IE'den yapıştırılmış metin almak için aşağıdakileri kullanabilirsiniz:

window.clipboardData.getData('Text');


0

Sadece yazmak için yeterince basit olmaz

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

}


0

Ayrıca ControlValueAccessor Arayüzünü ( https://angular.io/api/forms/ControlValueAccessor ) uygulayan bir yönerge de oluşturabilirsiniz .

Buradaki çalışma örneğine bakın: https://stackblitz.com/edit/angular-input-field-to-accept-only-numbers

'Girdi' olayını dinleyebilirsiniz ve anahtar kodlarını kontrol etmenize gerek yoktur. Kopyalama ve yapıştırmayı destekler ve ControlValueAccessor Arayüzü sayesinde Angular Forms API ile güzel bir şekilde bütünleşir.

Direktif:

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

Kullanım:

<input name="number" type="text" onlyNumber [(ngModel)]="someNumber">
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.