Angular2 - поле ввода для приема только чисел


86

Как в Angular 2 замаскировать поле ввода (текстовое поле), чтобы оно принимало только числа, а не алфавитные символы?

У меня есть следующий ввод HTML:

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

Вышеупомянутый ввод представляет собой общий текстовый ввод, который может использоваться как простое текстовое поле или как числовое поле, например, для отображения года.

Используя Angular 2, как я могу использовать тот же элемент управления вводом и применить какой-то фильтр / маску к этому полю, чтобы он принимал только числа?

Какими способами я могу этого добиться?

Примечание: мне нужно добиться этого, используя только текстовое поле и не используя тип ввода.


1
Вы могли бы просто использовать атрибут html? type = number
inoabrian

@inoabrian Я хочу добиться этого без использования числового типа.
Aniruddha Pondhe

Это может вам помочь: stackoverflow.com/questions/39799436/…
chandan7

Ответы:


112

Вы можете использовать директивы 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();
        }
      }
  }
}

и вам нужно записать имя директивы во входных данных как атрибут

<input OnlyNumber="true" />

не забудьте написать свою директиву в массиве объявлений вашего модуля.

При использовании регулярного выражения вам все равно понадобятся функциональные ключи

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
Замечательно. В любом случае я могу добиться того же, используя шаблоны RegEx?
Aniruddha Pondhe

3
Это не позволяет копипасту.
Shardul

@Shardul просто добавьте (e.keyCode == 86 && e.ctrlKey === true)к условиям, копирование работает, но вставка не работает
Аль-Мотафар

1
Как добавить пробел, плюс и минус?
Захидул Ислам Рухель


65

Если вам не нужна директива

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

в component.html

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

в 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
Проблема с этим подходом заключается в том, что ключевые события не фиксируют вставку пользователем или автоматическое заполнение поля ввода браузером. Так что это плохое решение.
Дэррин Хоскинг,

30

Я знаю, что это старый вопрос, но поскольку это обычная функция, я хочу поделиться внесенными мною модификациями:

  • Пользовательский десятичный разделитель (точка или запятая)
  • Поддержка только целых чисел или целых и десятичных чисел
  • Поддержка только положительных чисел или положительных и отрицательных чисел
  • Подтвердите, что знак минус (-) находится в начале
  • Поддержка вставки с помощью мыши (с некоторыми ограничениями, хотя https://caniuse.com/#feat=clipboard )
  • Поддержка командной клавиши Mac
  • Замените такие строки, как «.33» и «33.» для правильных версий: 0.33 и 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);
                }
            }
        }
    }
    

Применение:

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

Я изменил последнюю строку метода validatevalue, чтобы предотвратить добавление нуля за недопустимую вставку. if (valid) {this.hostElement.nativeElement ['value'] = value;}
Абдул Рехман Сайед,

не могли бы вы также добавить проверку перетаскивания? Кроме того, я заметил, что значение поля ввода изменяется на значение с заполнением 0 для ведущего и конечного десятичного разделителя, но значение не обновляется в переменной двусторонней привязки. например: [(NgModel)] = "myVariable", здесь, если мы введем .3 в поле ввода, значение при вводе текста изменится на 0,3 при размытии, но значение в myVariable все равно останется '.3'.
Sushmit Sagar 01

Отсутствует ввод Delete и Enter, но в любом случае решение очень хорошее
Олег Бондаренко

29

Я хотел бы опираться на ответ @omeralper, который, на мой взгляд, послужил хорошей основой для надежного решения.

Я предлагаю упрощенную и актуальную версию с последними веб-стандартами. Важно отметить, что event.keycode удален из веб-стандартов, и будущие обновления браузера могут больше не поддерживать его. См. Https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode.

Кроме того, метод

String.fromCharCode(e.keyCode);

не гарантирует, что keyCode, относящийся к клавише, нажатой пользователем, соответствует ожидаемой букве, указанной на клавиатуре пользователя, поскольку разные конфигурации клавиатуры приведут к тому, что конкретный код клавиши будет отличаться от символов. Это приведет к появлению ошибок, которые сложно идентифицировать, и которые могут легко нарушить функциональность для определенных пользователей. Скорее я предлагаю использовать event.key, см. Документы здесь https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Кроме того, нам нужно только, чтобы результирующий вывод был действительным десятичным числом. Это означает, что числа 1, 11.2, 5000.2341234 следует принимать, но значение 1.1.2 принимать нельзя.

Обратите внимание, что в своем решении я исключаю функции вырезания, копирования и вставки, поскольку оно открывает окна на наличие ошибок, особенно когда люди вставляют нежелательный текст в связанные поля. Для этого потребуется процесс очистки обработчика клавиш; что не входит в рамки этой темы.

Вот решение, которое я предлагаю.

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

Это действительно интересный подход. Есть ли у вас какие-либо предложения о том, как реализовать функцию копирования / вставки, не прибегая к более старым методам, таким как (e.keyCode == 67 && e.ctrlKey === true) ??
Ender2050

1
Я лично этого не пробовал, но вы можете точно так же прослушивать запускаемые события копирования / вставки. Они генерируют событие ClipboardEvent ( developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent ), которое содержит данные, которые копируются / вставляются. Единственный недостаток в том, что это все еще экспериментально и поддерживается только последними версиями
JeanPaul A.

Я пробовал аналогичный подход, но, к сожалению, он работает не во всех случаях. Ваша «следующая» переменная предполагает, что нажатый символ находится в конце текущего введенного значения. Это не всегда так. Например, если кто-то набирает 100, а затем решает сделать это 1100, добавляя 1 впереди. Ваша "следующая" переменная будет неправильной (1001).
Карлос Родригес

Поскольку «следующее» значение используется только для проверки того, является ли введенная сумма допустимой десятичной дробью (а не для установки значения), добавление его в конце не повлияет на проверку регулярного выражения.
JeanPaul A.

Только я хотел бы добавить эту строку для применения в элементе управления вводом. <input myNumberOnly type = "text" id = "yourId">
Lrodriguez84

17

Более лаконичное решение. Попробуйте эту директиву.

Также может использоваться, если вы используете 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, ''));
  }
}

Используйте его на своих входах следующим образом:

<input matInput formControlName="aNumberField" numberOnly>

1
Хотя это решение работает, оно дважды запускает события изменения модели, что говорит о том, что подход с использованием регулярного выражения является правильным, вот версия, которая НЕ запускает события изменения модели дважды: stackblitz.com/edit/…
ntziolis

К комментарию ntziolis: Пока решение Бена Гулапы работает для меня. Но решение, на которое ссылается ntziolis, - нет. Простите меня, если я ошибаюсь, но похоже, что проблема с кодом в приведенной выше ссылке на stackblitz, по крайней мере для меня, заключалась в том, что последний нежелательный символ, который я набрал, хотя он никогда не отображался в пользовательском интерфейсе, каким-то образом получил поместить в связанную переменную моего компонента. Просто последний нежелательный персонаж.
user2367418

Чтобы продолжить мой комментарий: Использование Angular 7 и ввода текста HMTL ограничено двумя символами.
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

Вам нужно использовать type = "number" вместо текста. Вы также можете указать максимальное и минимальное количество

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

2
Я хочу добиться этого без использования числового типа.
Aniruddha Pondhe

3
Поддержка числового типа по-прежнему не работает, как описано в этом ответе: stackoverflow.com/a/14995890/1156185
Николас Форни,

9
Недостатком type="number"является то , что она принимает характер eв рамках научной нотации
user776686

12

Вы можете добиться этого вот так

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

Надеюсь, что это поможет вам.


не могли бы вы подробнее рассказать об этом? что делает event.charCode == 8?
bosari 06

9

Вы можете использовать регулярное выражение:

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

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

1
да, это полезно, но я хочу (.) десятичное число также в моем поле ввода
rinku Choudhary

6

Используйте patternатрибут для ввода, как показано ниже:

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

это не работает. когда вы начинаете печатать, вы вводите символы, которые
говорят о

6

Я знаю, что у этого есть много ответов, но мне нужно было обработать следующее (что, похоже, ни один из ответов не поддерживал полностью):

  • Поддержка текстового поля с возможностью для многострочного
  • Десятичные или отрицательные числа
  • Максимальная длина в строке
  • Кроссбраузерная поддержка (Chrome, Edge, IE 11)
  • Обработка операций и событий вырезания / вставки

Решение позволяет мне определить текстовое поле следующим образом:

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

Или, если мне просто нужны положительные целые числа

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

Вот моя директива:

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

Для этого я привязал функцию к методу onInput следующим образом:

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

Вот пример внутри моей формы:

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

Затем я добавил в свой компонент следующую функцию:

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

Это регулярное выражение /[^0-9]/gищет все, что не является числом, и с помощью .replaceя установил его замену ничем. Поэтому, когда пользователь пытается ввести символ, не являющийся числом (в данном случае символ, который не равен девяти), это выглядит так, как будто в текстовом поле ничего не происходит.


4

Что ж, спасибо JeanPaul A. и rdanielmurphy. Я создал свою собственную директиву Custom для ограничения поля ввода только числом. Также добавлены атрибуты ввода max и min. Будет работать и в angular 7.

Угловой

    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

Современный подход для лучшего ответа (без устаревшего 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
Это круто! @Directive ({selector: "[inputNumericInput]"}) класс экспорта NumericInputDirective {@HostListener ()}
Нейт,

1
Работает хорошо. Только побочный эффект наблюдается при копипасте. Это позволяет копировать и вставлять внешние нечисловые строки. Погуглил и нашел лучшее решение, которое решает эту проблему
vinsinraw

4

Произвольная директива RegExp

Вот небольшая директива, которая использует произвольное регулярное выражение и блокирует пользователя для ввода недопустимого значения

Чтобы замаскировать только числа, используйте

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

К сожалению, вы можете обмануть это решение, рассылая спам с циркумфлексом + все, что вы хотите написать.
ProgFroz,

3

Просто создайте директиву и добавьте ниже hostlistener:

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

Замените недопустимый текст пустым. Все клавиши и комбинации клавиш теперь будут работать во всех браузерах до IE9.


Если начать с char, char не будет добавляться, но счет длины модели занимает 1. Как это решить? Также, если элемент имеет максимальную длину, скопируйте и вставьте смешанный контент, количество моделей будет максимальной длиной. Например, максимальная длина равна 10, затем скопируйте и вставьте 1238261jhgjh12987 для ввода, добавит только 123816, но длина модели займет 10. Какие-либо решения?
Сатиш Натараджан

3

Шаблон для действительного шаблона номера мобильного телефона ('^ ((\ + 91 -?) | 0)? [0-9] {10} $')

Шаблон для принятия только числа из шаблона текстового поля ('[0-9] *')

скороговорка для приема только номера с определенным номером, например: Pincode. шаблон ('^ [0-9] {5} $')


2

Я внес некоторые изменения в указанную выше директиву и реализовал 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();
    }

  }
}

как указать значение максимальной длины из поля ввода
Джейсон Броуди,

<input id = "COMN" class = "wb-e-inp-1__input" type = "text" appNumberOnly maxlength = "10" /> работает
Джейсон Броди

1

из ответа @omeralper. Я немного изменил, чтобы не принимать период ascii (код ключа 110,190). и используйте let ch = (e.key); для сравнения с регулярным выражением, когда вы меняете язык (например, тайский или японский язык), он не принимает символы этого языка

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

надеюсь, что это поможет :)


1

Вы можете создать этот валидатор и импортировать его в свой компонент.
В основном проверяет строку ввода формы:

  • проверьте, нет ли точки
  • преобразует строку в число
  • чек - целое число
  • чек больше нуля

Чтобы реализовать это в своем проекте:

  1. предлагаемый путь в папке вашего приложения: src / app / validators / number.validator.ts
  2. импортировать в свой компонент

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

  3. добавить его в форму
    inputNumber: ['', [NumberValidator.isInteger]],
  4. если вы не хотите отображать недопустимый символ, привяжите его (change)="deleteCharIfInvalid()"к вводу, если form.get('inputNumber').hasError('isInteger')есть true, удалите последний вставленный символ.
// 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;
    }        
}

Не Number.isInteger(Math.floor(control.value))всегда будет правдой? Я думаю, так должно быть parseFloat.
AndyTheEntity

1

С поддержкой очистки вставленного содержимого:

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

Вот простой: Простая директива При событии keydown она проверяет, что длина ключа равна единице, а ключ не является числом, preventDefault()и он не отображает этот символ.

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

Ограничения: это позволит вставлять с помощью мыши, таким образом, примет другие символы. Чтобы избежать этого, вы можете передать модель в качестве входных данных в директиву иngOnChage изменить значение этой модели только на числа:

Как показано ниже:

РЕДАКТИРОВАТЬ: добавлен код для обнаружения изменений в модели и обновления входного значения

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, char не будет добавляться, но счет длины модели занимает 1. Как это решить?
Сатиш Натараджан

когда вы проверяете длину, она остается 0 в директиве до и после внесения изменений. Если в какой-то момент это один, он должен быстро вернуться к 0.
Lahar Shah

Нет, это не так. Просто попробуйте привязать numModel.length в шаблоне и проверить количество длин
Сатиш Натараджан

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

      }
    }

Директива - также лучший способ сделать это


1

Кастинг, потому что он работает также с ведущим 0, например 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, ''));
  }
}

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

или: 2. в HTML-файле:

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

в файле ts:

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

Это 2 решения работают


Используйте блоки кода для форматирования фрагментов кода.
YuS

0

fromCharCode возвращает 'a' при нажатии на цифровую клавиатуру '1', поэтому этого метода следует избегать

(администратор: не мог комментировать как обычно)


0

Я видел много комментариев об обработке копирования / вставки.

Чтобы отказаться от ответа @omeralper, вы можете добавить обработчик события вставки в директиву onlyNumber для обработки копирования / вставки:

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

Это позволит копировать и вставлять контент в текстовое поле, ТОЛЬКО если это число. Это самое простое решение. Изменение содержимого буфера обмена для удаления нечисловых значений намного сложнее и, возможно, того не стоит.

Чтобы получить вставленный текст из IE, вы можете использовать следующее:

window.clipboardData.getData('Text');



0

Вы также можете создать директиву, которая реализует интерфейс ControlValueAccessor ( https://angular.io/api/forms/ControlValueAccessor ).

См. Рабочий пример здесь: https://stackblitz.com/edit/angular-input-field-to-accept-only-numbers

Вы можете прослушивать событие ввода, и вам не нужно проверять коды клавиш. Он поддерживает копирование и вставку и прекрасно интегрируется с API Angular Forms благодаря интерфейсу ControlValueAccessor.

Директива:

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

Применение:

<input name="number" type="text" onlyNumber [(ngModel)]="someNumber">
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.