2017-01-04 38 views
18

Trong Angular2, làm thế nào tôi có thể che dấu một trường đầu vào (hộp văn bản) sao cho nó chỉ chấp nhận số và không phải bảng chữ cái?Angular2 - Trường nhập để chỉ chấp nhận số

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

Các đầu vào ở trên là một đầu vào văn bản chung chung mà có thể hoặc được sử dụng như một trường văn bản đơn giản hoặc như một số lĩnh vực, (ví dụ để hiển thị các năm) .

Sử dụng góc 2, làm cách nào tôi có thể sử dụng cùng một điều khiển nhập 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 số? Những cách khác nhau mà 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.

+0

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

+0

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

+0

Điều này có thể giúp bạn: http: // stackoverflow.com/questions/39799436/angular-2-custom-validator-check-if-the-input-value-là-một-số nguyên – chandan7

Trả lời

3

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

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

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

+0

không hoạt động với IE – keepscoding

+0

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

50

Bạn có thể sử dụng chỉ thị angular2. Plunkr

import { Directive, ElementRef, HostListener, Input } from '@angular/core'; 

@Directive({ 
    selector: '[OnlyNumber]' 
}) 
export class OnlyNumber { 

    constructor(private el: ElementRef) { } 

    @Input() OnlyNumber: boolean; 

    @HostListener('keydown', ['$event']) onKeyDown(event) { 
    let e = <KeyboardEvent> event; 
    if (this.OnlyNumber) { 
     if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 || 
     // Allow: Ctrl+A 
     (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) || 
     // Allow: Ctrl+C 
     (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) || 
     // Allow: Ctrl+V 
     (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) || 
     // Allow: Ctrl+X 
     (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) || 
     // Allow: home, end, left, right 
     (e.keyCode >= 35 && e.keyCode <= 39)) { 
      // let it happen, don't do anything 
      return; 
     } 
     // Ensure that it is a number and stop the keypress 
     if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { 
      e.preventDefault(); 
     } 
     } 
    } 
} 

và bạn cần phải viết tên chỉ ở đầu vào của bạn như một thuộc tính

<input OnlyNumber="true" /> 

đừng quên để viết chỉ thị của bạn trong tờ khai hàng loạt các mô-đun của bạn.

Bằng cách sử dụng regex bạn vẫn sẽ 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 cùng một bằng cách sử dụng mẫu RegEx? –

+0

@AniruddhaPondhe Tôi đã cập nhật câu trả lời cho regex. – omeralper

+2

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

7

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

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

niềm hy vọng này này sẽ giúp bạn.

+0

bạn có thể giải thích về điều này không? event.charCode == 8 đang làm gì? – basari66

0

từ câu trả lời của @omeralper. Tôi thay đổi một chút mà sẽ không chấp nhận ascii thời gian (mã khóa 110.190). và sử dụng let ch = (e.key); để so sánh với biểu hiện thường xuyên khi bạn thay đổi ngôn ngữ (chẳng hạn như Thái Lan hoặc tiếng Nhật) nó sẽ không chấp nhận tính cách 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 sự giúp đỡ này :)

19

Tôi muốn xây dựng dựa trên câu trả lời được đưa ra bởi @omeralper, theo ý kiến ​​của tôi, cung cấp một nền tảng tốt cho một giải pháp vững chắc.

Điều tôi đang đề xuất là một phiên bản đơn giản 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ị loại bỏ 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 này

String.fromCharCode(e.keyCode); 

không đảm bảo rằng các keyCode liên quan đến phím được nhấn bởi các bản đồ dùng để bức thư dự kiến ​​sẽ được xác định trên bàn phím của người dùng, vì cấu hình bàn phím khác nhau sẽ cho kết quả trong một mã khóa đặc biệt khác nhau.Sử dụng điều này sẽ giới thiệu 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ào đó tôi đề 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 phải được chấp nhận, nhưng giá trị 1.1.2 không được chấp nhận.

Lưu ý rằng trong giải pháp của tôi, tôi không bao gồm 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 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 một trình xử lý khóa; đó 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(); 
     } 
    } 
} 
+0

Đâ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 sử dụng các phương pháp cũ hơn như (e.keyCode == 67 && e.ctrlKey === true) ?? – Ender2050

+1

Tôi đã không cố gắng cá nhân này, tuy nhiên bạn có thể tương tự lắng nghe các sự kiện sao chép/dán được kích hoạt. Họ tạo ra một ClipboardEvent (https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent) có 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ử nghiệm và được hỗ trợ bởi các trình duyệt mới nhất - https://caniuse.com/#search=paste –

+0

Tôi đã thử một cách tiếp cận tương tự nhưng tiếc là điều này không làm việc 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ẽ xuất hiện ở cuối giá trị hiện được nhập. Đây không phải lúc nào cũng vậy. Ví dụ, nếu ai đó gõ 100, và sau đó quyết định làm cho nó 1100 bằng cách gắn thêm 1 vào trước. Biến "tiếp theo" của bạn sẽ không chính xác (1001). –

0

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 bạn.
Về cơ bản xác nhận chuỗi dạng đầu vào:

  • kiểm tra không có dấu chấm
  • chuyển xâu lên vị trí số
  • séc là số nguyên
  • séc là lớn hơn không

Thực hiện trong dự án của bạn:

  1. gợi ý đường dẫn trong thư mục ứng dụng của bạn: src/app/xác nhận/number.validator.ts
  2. nhập khẩu trong thành phần của bạn

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

  3. thêm nó vào các hình thức kiểm soát
    inputNumber: ['', [NumberValidator.isInteger]],
  4. nếu bạn không muốn hiển thị thẻ không hợp lệ, hãy gắn một (change)="deleteCharIfInvalid()" vào đầu vào, nếu form.get('inputNumber').hasError('isInteger')true, hãy xóa bỏ ký tự cuối cùng được chèn vào.
// 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; 
    }   
} 
+0

Sẽ không 'Number.isInteger (Math.floor (control.value))' luôn luôn đúng? Tôi nghĩ rằng nó nên được 'parseFloat' thay thế. – AndyTheEntity

1

Chỉ Tạo một chỉ thị và thêm vào dưới đây 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ệ với sản phẩm nào. Tất cả các phím và tổ hợp phím bây giờ sẽ hoạt động trên tất cả các trình duyệt cho đến IE9.

0

fromCharCode trả về 'a' khi nhấn vào numpad '1' để methoid này nên tránh

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

2

Để thực hiện điều này, tôi bị ràng buộc một chức năng với phương pháp onInput như thế này:

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

Dưới đây là ví dụ bên trong hình thức 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 được thêm vào các chức năng sau đây để thành phần của tôi:

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

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

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

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

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

Với sự hỗ trợ cho sanitizing 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(); 
     } 
    } 

} 
0

Đây là điều dễ dàng: Đơn giản chỉ Mở sự kiện KeyDown nó sẽ kiểm tra chiều 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 ám rằng char.

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 sử dụng một con chuột như vậy sẽ chấp nhận char khác. Để tránh điều đó, bạn có thể vượt qua các mô hình làm đầu vào cho chỉ thị và ngOnChage với giá trị mô hình thay đổi chỉ số:

Giống như dưới đây:

EDIT: Thêm code để phát hiện sự 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" /> 
0

sử dụng chỉ thị để hạn chế người dùng chỉ nhập số theo cách sau:

.directive('onlyNumber', function() { 
    var regExp = /^[0-9]*$/; 
    return { 
     require: '?ngModel', 
     restrict: 'A', 
     priority: 1, 
     link: function (scope, elm, attrs, ctrl) { 
      ctrl.$validators.onlyNumber= function (modalValue) { 
       return ctrl.$isEmpty(modalValue) || regExp.test(modalValue); 
      }; 
     } 
    }; 
    }) 

Trong HTML:

<input id="txtRollNumber" type="text" name="rollNumber" placeholder="Enter roll number*" ng-model="rollNumber" class="form-control" maxlength="100" required only-number /> 
Các vấn đề liên quan