Angular2 - Trường nhập để chỉ chấp nhận các số


87

Trong Angular 2, làm cách nào để tôi có thể che dấu một trường nhập liệu (hộp văn bản) để nó chỉ chấp nhận các số chứ không phải các ký tự chữ cái?

Tôi có đầu vào HTML sau:

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

Đầu vào ở trên là kiểu nhập văn bản chung có thể được sử dụng như một trường văn bản đơn giản hoặc như một trường số, chẳng hạn, để hiển thị năm.

Sử dụng Angular 2, làm cách nào tôi có thể sử dụng cùng một điều khiển đầu vào và áp dụng một số loại bộ lọc / mặt nạ trên trường này, sao cho nó chỉ chấp nhận các số?

Những cách khác nhau để tôi có thể đạt được điều này là gì?

Lưu ý: Tôi cần đạt được điều này chỉ bằng cách sử dụng hộp văn bản và không sử dụng loại số đầu vào.


1
Bạn có thể chỉ sử dụng thuộc tính html không? type = number
inoabrian

@inoabrian Tôi muốn đạt được điều này mà không cần sử dụng loại số.
Aniruddha Pondhe

Điều này có thể giúp bạn: stackoverflow.com/questions/39799436/…
chandan7

Câu trả lời:


112

Bạn có thể sử dụng chỉ thị angle2. 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();
        }
      }
  }
}

và bạn cần viết tên chỉ thị trong đầu vào của mình dưới dạng một thuộc tính

<input OnlyNumber="true" />

đừng quên viết chỉ thị của bạn trong mảng khai báo của mô-đun của bạn.

Bằng cách sử dụng regex, bạn vẫn cần các phím chức năng

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
Thật tuyệt. Bất kỳ cách nào tôi có thể đạt được điều tương tự bằng cách sử dụng các mẫu RegEx?
Aniruddha Pondhe

3
Nó không cho phép sao chép-dán.
Shardul

@Shardul chỉ cần thêm (e.keyCode == 86 && e.ctrlKey === true)điều kiện, sao chép đang làm việc nhưng dán không hoạt động
Al-Mothafar

1
Làm cách nào để thêm dấu cách, dấu cộng và dấu trừ?
Zahidul Islam Ruhel


65

Nếu bạn không muốn một chỉ thị

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

trong component.html

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

trong 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
Vấn đề với cách tiếp cận này là các sự kiện chính không bắt người dùng dán hoặc trình duyệt tự động điền vào trường nhập. Vì vậy, đây là một giải pháp kém.
Darryn Hosking

30

Tôi biết đây là một câu hỏi cũ, nhưng vì đây là một tính cách phổ biến, tôi muốn chia sẻ những sửa đổi mà tôi đã thực hiện:

  • Dấu phân tách thập phân tùy chỉnh (dấu chấm hoặc dấu phẩy)
  • Chỉ hỗ trợ cho số nguyên hoặc số nguyên và số thập phân
  • Chỉ hỗ trợ cho các số dương hoặc tích cực và phủ định
  • Xác thực dấu trừ (-) ở đầu
  • Hỗ trợ dán chuột (với một số hạn chế mặc dù https://caniuse.com/#feat=clipboard )
  • Hỗ trợ phím lệnh Mac
  • Thay thế các chuỗi như ".33" và "33." cho các phiên bản chính xác: 0.33 và 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);
                }
            }
        }
    }
    

Sử dụng:

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

Tôi đã thay đổi dòng cuối cùng của phương thức xác nhận giá trị để ngăn việc thêm số 0 cho quá trình dán không hợp lệ. if (hợp lệ) {this.hostElement.nativeElement [ 'giá trị'] = value;}
Abdul Rehman Sayed

bạn cũng có thể thêm xác nhận kéo và thả được không? Ngoài ra, tôi nhận thấy rằng giá trị trường đầu vào thay đổi thành giá trị đệm 0 cho dấu phân tách thập phân ở đầu và cuối nhưng giá trị không cập nhật trong biến liên kết hai chiều. ví dụ: [(NgModel)] = "myVariable", ở đây, nếu chúng ta nhập .3 vào trường đầu vào, giá trị trong đầu vào văn bản thay đổi thành 0,3 khi làm mờ nhưng giá trị trong myVariable vẫn giữ nguyên '.3'.
Sushmit Sagar

Đầu vào Delete và Enter bị thiếu, nhưng dù sao thì giải pháp cũng rất tốt
Oleg Bondarenko

29

Tôi muốn xây dựng câu trả lời do @omeralper đưa ra, theo quan điểm của tôi, câu trả lời này đã cung cấp nền tảng tốt cho một giải pháp vững chắc.

Những gì tôi đang đề xuất là một phiên bản đơn giản hóa và cập nhật với các tiêu chuẩn web mới nhất. Điều quan trọng cần lưu ý là event.keycode bị xóa khỏi các tiêu chuẩn web và các bản cập nhật trình duyệt trong tương lai có thể không hỗ trợ nó nữa. Xem https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode

Hơn nữa, phương pháp

String.fromCharCode(e.keyCode);

không đảm bảo rằng Mã khóa liên quan đến phím được người dùng nhấn ánh xạ tới ký tự mong đợi như được xác định trên bàn phím của người dùng, vì các cấu hình bàn phím khác nhau sẽ dẫn đến một mã khóa cụ thể các ký tự khác nhau. Sử dụng điều này sẽ tạo ra các lỗi khó xác định và có thể dễ dàng phá vỡ chức năng cho một số người dùng nhất định. Thay vì tôi đang đề xuất sử dụng event.key, hãy xem tài liệu tại đây https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Hơn nữa, chúng tôi chỉ muốn kết quả đầu ra là một số thập phân hợp lệ. Điều này có nghĩa là các số 1, 11.2, 5000.2341234 nên được chấp nhận, nhưng không nên chấp nhận giá trị 1.1.2.

Lưu ý rằng trong giải pháp của tôi, tôi không loại trừ chức năng cắt, sao chép và dán vì nó mở cửa sổ cho các lỗi, đặc biệt là khi mọi người dán văn bản không mong muốn vào các trường được liên kết. Điều đó sẽ yêu cầu một quá trình dọn dẹp trên trình xử lý keyup; mà không phải là phạm vi của chủ đề này.

Đây là giải pháp tôi đang đề xuất.

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

Đây là một cách tiếp cận thực sự thú vị. Bạn có bất kỳ đề xuất nào về cách triển khai chức năng sao chép / dán mà không cần dùng đến các phương pháp cũ hơn như (e.keyCode == 67 && e.ctrlKey === true) không ??
Ender2050

1
Cá nhân tôi chưa thử điều này, tuy nhiên bạn cũng có thể nghe các sự kiện sao chép / dán được kích hoạt. Họ tạo ClipboardEvent ( developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent ) chứa dữ liệu đang được sao chép / dán. Hạn chế duy nhất là điều này vẫn còn thực nghiệm và được hỗ trợ bởi các trình duyệt mới nhất chỉ - caniuse.com/#search=paste
JeanPaul A.

Tôi đã thử một cách tiếp cận tương tự nhưng tiếc là cách này không hoạt động cho mọi trường hợp. Biến "tiếp theo" của bạn giả định rằng ký tự được nhấn sẽ ở cuối giá trị hiện được nhập. Điều này không phải luôn luôn như vậy. Ví dụ: nếu ai đó nhập 100 và sau đó quyết định đặt nó thành 1100 bằng cách thêm 1 vào phía trước. Biến "tiếp theo" của bạn sẽ không chính xác (1001).
Carlos Rodriguez

Vì giá trị 'tiếp theo' chỉ được sử dụng để kiểm tra xem số tiền đầu vào có phải là số thập phân hợp lệ hay không (và không phải để đặt giá trị), việc thêm nó vào cuối sẽ không thay đổi xác thực regex.
JeanPaul A.

Chỉ tôi muốn thêm dòng này để áp dụng trong kiểm soát đầu vào. <input myNumberOnly type = "text" id = "yourId">
Lrodriguez84

17

Một giải pháp ngắn gọn hơn. Hãy thử chỉ thị này.

Cũng có thể được sử dụng nếu bạn đang sử dụng 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, ''));
  }
}

Sử dụng nó trên đầu vào của bạn như thế này:

<input matInput formControlName="aNumberField" numberOnly>

1
Trong khi giải pháp này hoạt động nó gây nên sự kiện thay đổi mô hình hai lần, mà nói cách tiếp cận của việc sử dụng regex là một trong những quyền, đây là một phiên bản mà không mô hình lửa thay đổi sự kiện hai lần: stackblitz.com/edit/...
ntziolis

Theo nhận xét của ntziolis: Cho đến nay giải pháp của Ben Gulapa đang làm việc cho tôi. Nhưng giải pháp được tham chiếu bởi ntziolis thì không. Thứ lỗi cho tôi nếu tôi sai, nhưng có vẻ như vấn đề với mã tại liên kết ở trên tới stackblitz, ít nhất là đối với tôi, đó là ký tự không mong muốn cuối cùng mà tôi đã nhập, mặc dù nó không hiển thị bao giờ trong giao diện người dùng, bằng cách nào đó. đưa vào biến bị ràng buộc của thành phần của tôi. Chỉ là nhân vật không mong muốn cuối cùng.
user2367418

Để tiếp tục nhận xét của tôi: Sử dụng Angular 7 và văn bản đầu vào HMTL giới hạn trong hai ký tự.
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

Bạn cần sử dụng loại = "số" thay vì văn bản. Bạn cũng có thể chỉ định số tối đa và số tối thiểu

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

2
Tôi muốn đạt được điều này mà không cần sử dụng kiểu số.
Aniruddha Pondhe

3
Hỗ trợ cho loại số vẫn còn khá nhiều lỗi như được mô tả trong câu trả lời này: stackoverflow.com/a/14995890/1156185
Nicolas Forney

9
Nhược điểm của type="number"là nó chấp nhận nhân vật enhư một phần của ký hiệu khoa học
user776686

12

bạn có thể đạt được nó như thế này

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

Hy vọng điều này sẽ giúp bạn.


bạn có thể nói rõ hơn về điều này? event.charCode == 8 đang làm gì?
bosari

9

Bạn có thể sử dụng regex:

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

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

1
vâng đó là hữu ích nhưng tôi muốn thập phân cũng trong lĩnh vực đầu vào của tôi (.)
rinku Choudhary

6

Sử dụng patternthuộc tính cho đầu vào như dưới đây:

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

nó không làm việc. khi bạn bắt đầu nhập, bạn gõ sai các ký tự
Seyed-Amir-Mehrizi

6

Tôi biết điều này có rất nhiều câu trả lời, nhưng tôi cần phải xử lý những điều sau (mà không có câu trả lời nào dường như hỗ trợ đầy đủ):

  • Hỗ trợ vùng văn bản với tùy chọn cho nhiều dòng
  • Số thập phân hoặc số âm
  • Độ dài tối đa trên mỗi dòng
  • Hỗ trợ nhiều trình duyệt (Chrome, Edge, IE 11)
  • Xử lý các hoạt động và sự kiện cắt / dán

Giải pháp cho phép tôi xác định một vùng văn bản như thế này:

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

Hoặc nếu tôi chỉ muốn số nguyên dương

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

Đây là chỉ thị của tôi:

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

Để thực hiện điều này, tôi đã liên kết một hàm với phương thức onInput như sau:

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

Đây là ví dụ bên trong biểu mẫu của tôi:

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

Sau đó, tôi đã thêm chức năng sau vào thành phần của mình:

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

Regex này /[^0-9]/gtìm kiếm bất cứ thứ gì không phải là số và .replacetôi sử dụng nó để thay thế bằng số không. Vì vậy, khi người dùng cố gắng nhập một ký tự không phải là số (trong trường hợp này là ký tự không phải từ 0 đến chín), nó sẽ xuất hiện như thể không có gì xảy ra trong hộp văn bản.


4

Cảm ơn JeanPaul A. và rdanielmurphy. Tôi đã tạo chỉ thị Tùy chỉnh của riêng mình để chỉ giới hạn trường đầu vào ở số. Cũng đã thêm các thuộc tính đầu vào tối đa và tối thiểu. Cũng sẽ hoạt động trong góc 7.

Angular

    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

Một cách tiếp cận hiện đại cho câu trả lời tốt nhất (không dùng Mã 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
Điều này thật tuyệt! @Directive ({selector: "[inputNumericInput]"}) xuất lớp NumericInputDirective {@HostListener ()}
Nate

1
Hoạt động tốt. Chỉ có tác dụng phụ được quan sát thấy trong sao chép dán. Nó cho phép dán sao chép các chuỗi không phải số bên ngoài. Googled và tìm thấy giải pháp tốt hơn giải quyết vấn đề này @ stackblitz.com/edit/…
vinsinraw

4

Chỉ thị RegExp tùy ý

Đây là chỉ thị nhỏ sử dụng regexp tùy ý và chặn người dùng nhập giá trị không hợp lệ

Để che số chỉ sử dụng

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

Thật không may, bạn có thể lừa giải pháp này bằng cách gửi spam dấu ngoặc kép + bất cứ thứ gì bạn muốn viết.
ProgFroz

3

Chỉ cần Tạo một chỉ thị và thêm vào bên dưới hostlistener:

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

Thay thế văn bản không hợp lệ bằng trống. Tất cả các phím và tổ hợp phím hiện sẽ hoạt động trên tất cả các trình duyệt cho đến IE9.


Nếu kiểu bắt đầu bằng char, char sẽ không nối thêm nhưng đếm chiều dài mô hình mất 1. Làm thế nào để giải quyết điều đó ?. Ngoài ra, nếu phần tử có độ dài tối đa, sau đó sao chép và dán nội dung hỗn hợp, số lượng mô hình sẽ là độ dài tối đa. Ví dụ: độ dài tối đa có 10, sau đó sao chép và dán 1238261jhgjh12987 vào đầu vào sẽ chỉ thêm 123816 nhưng độ dài của mô hình sẽ mất 10. Có giải pháp nào không?
Satheesh Natarajan

3

Mẫu cho mẫu Số di động hợp lệ ('^ ((\ + 91 -?) | 0)? [0-9] {10} $')

Mẫu chỉ chấp nhận số từ mẫu hộp văn bản ('[0-9] *')

pattern cho chỉ chấp nhận số với số cụ thể, ví dụ: Pincode. mẫu ('^ [0-9] {5} $')


2

Tôi đã thực hiện một số sửa đổi trong chỉ thị trên và triển khai 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();
    }

  }
}

làm thế nào để cung cấp cho giá trị chiều dài tối đa khỏi trường nhập
Jason Brody

<input id = "COMN" class = "wb-e-inp-1__input" type = "text" appNumberOnly maxlength = "10" /> làm việc
Jason Brody

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

hoặc: 2. trong Tệp HTML:

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

trong Tập tin ts:

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

2 giải pháp này hoạt động


Vui lòng sử dụng các khối mã để định dạng các đoạn mã của bạn.
YuS

1

từ câu trả lời của @omeralper. Tôi thay đổi một chút sẽ không chấp nhận ascii dấu chấm (mã khóa 110,190). và sử dụng let ch = (e.key); để so sánh với biểu thức chính quy khi bạn thay đổi ngôn ngữ (chẳng hạn như tiếng Thái hoặc tiếng Nhật), nó sẽ không chấp nhận ký tự của những ngôn ngữ đó

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

hy vọng điều này giúp đỡ :)


1

Bạn có thể tạo Trình xác thực này và nhập nó vào thành phần của mình.
Về cơ bản xác nhận chuỗi nhập biểu mẫu:

  • kiểm tra không có dấu chấm
  • chuyển đổi chuỗi thành số
  • kiểm tra là một số nguyên
  • séc lớn hơn 0

Để thực hiện nó trong dự án của bạn:

  1. đường dẫn được đề xuất trong thư mục ứng dụng của bạn: src / app / validators / number.validator.ts
  2. nhập trong thành phần của bạn

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

  3. thêm nó vào điều khiển biểu mẫu
    inputNumber: ['', [NumberValidator.isInteger]],
  4. nếu bạn không muốn hiển thị char không hợp lệ, hãy liên kết a (change)="deleteCharIfInvalid()"với đầu vào, nếu form.get('inputNumber').hasError('isInteger')true, hãy xóa char cuối cùng được chèn.
// 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;
    }        
}

Sẽ không Number.isInteger(Math.floor(control.value))phải lúc nào cũng đúng? Tôi nghĩ nó nên được parseFloatthay thế.
AndyTheEntity,

1

Với sự hỗ trợ để khử trùng nội dung đã dán:

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

Đây là một trong những điều dễ dàng: Chỉ thị đơn giản Trong sự kiện keydown, nó kiểm tra độ dài của một khóa là một và khóa không phải là một số preventDefault()và nó sẽ không hiển thị ký tự đó.

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

Hạn chế: Nó sẽ cho phép dán bằng chuột theo cách đó sẽ chấp nhận các ký tự khác. Để tránh điều đó, bạn có thể chuyển mô hình làm đầu vào cho chỉ thị vàngOnChage thay đổi giá trị của mô hình đó thành chỉ các số:

Như bên dưới:

CHỈNH SỬA: Đã thêm Mã để phát hiện thay đổi trong Mô hình và cập nhật giá trị của đầu vào

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

Nếu bắt đầu kiểu với char, char sẽ không nối thêm nhưng đếm chiều dài mô hình mất 1. Làm thế nào để giải quyết điều đó?
Satheesh Natarajan

khi nào bạn kiểm tra độ dài, nó vẫn là 0 trong chỉ thị trước và sau khi thực hiện thay đổi. Nếu tại một thời điểm nào đó, nó sẽ trở về 0 một cách nhanh chóng.
Lahar Shah

Không, không phải. Chỉ cần cố gắng để ràng buộc numModel.length trong mẫu và kiểm tra số chiều dài
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();
          }
        };

      }
    }

Chỉ thị cũng là một cách tốt nhất để làm điều đó


1

Truyền vì nó cũng hoạt động với số 0 đứng đầu như 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, ''));
  }
}

0

fromCharCode trả về 'a' khi nhấn vào numpad '1', vì vậy nên tránh sử dụng methoid này

(admin: không thể bình luận như bình thường)


0

Tôi thấy rất nhiều bình luận về việc xử lý sao chép / dán.

Để loại bỏ câu trả lời @omeralper, bạn có thể thêm trình xử lý sự kiện dán vào chỉ thị onlyNumber để xử lý sao chép / dán:

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

Điều này sẽ chỉ cho phép nội dung được sao chép và dán vào hộp văn bản CHỈ nếu đó là một số. Đó là giải pháp đơn giản nhất. Thay đổi nội dung của khay nhớ tạm để xóa các số không phải là số phức tạp hơn rất nhiều và có thể không đáng.

Để dán văn bản từ IE, bạn có thể sử dụng như sau:

window.clipboardData.getData('Text');


0

Sẽ không đủ đơn giản chỉ để viết

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

}


0

Bạn cũng có thể tạo một chỉ thị triển khai Giao diện ControlValueAccessor ( https://angular.io/api/forms/ControlValueAccessor ).

Xem ví dụ làm việc tại đây: https://stackblitz.com/edit/angular-input-field-to-accept-only-numbers

Bạn có thể nghe sự kiện 'đầu vào' và không cần kiểm tra mã khóa. Nó hỗ trợ sao chép & dán và tích hợp độc đáo với API Angular Forms do Giao diện ControlValueAccessor.

Chỉ thị:

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

Sử dụng:

<input name="number" type="text" onlyNumber [(ngModel)]="someNumber">
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.