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 = число
іноабрианець

@inoabrian Я хочу досягти цього, не використовуючи тип числа.
Аніруддха Пондхе

Це може допомогти вам: stackoverflow.com/questions/39799436 / ...
chandan7

Відповіді:


112

Ви можете використовувати директиви angular2. Плункр

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?
Аніруддха Пондхе

3
Він не дозволяє копіювати-вставляти.
Шардул

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

1
Як додати пробіл, плюс і мінус?
Zahidul Islam Ruhel


65

Якщо ви не хочете директиви

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

у компоненті.html

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

в компонент.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'.
Сушміт Сагар

Введення "Видалити та ввести" відсутнє, але в будь-якому випадку рішення є дуже хорошим
Олег Бондаренко

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 ), який містить дані, які копіюються / вставляються. Єдиним недоліком є те, що це все ще експериментальна і підтримується останніми браузерами тільки - caniuse.com/#search=paste
JeanPaul А.

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

Оскільки значення "next" використовується лише для того, щоб перевірити, чи введена сума є дійсним десятковим числом (а не для встановлення значення), додавання його в кінці не змінить перевірку регулярного виразу.
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
Я хочу досягти цього, не використовуючи тип числа.
Аніруддха Пондхе

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

9

Ви можете використовувати регулярний вираз:

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

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

1
так, це корисно, але я хочу (.) десятковий
знак

6

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

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

це не працює. коли ви починаєте друкувати, ви вводите символи, що це неправильно
Seyed-Amir-Mehrizi

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

Ну спасибі ЖанПолу А. та рданіельмурфі. Я створив власну спеціальну директиву для обмеження поля введення лише числом. Також додано вхідні атрибути max та min. Також буде працювати в кутовій 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 ()}
Nate,

1
Працює добре. Тільки побічний ефект, який спостерігається при копіюванні пасти. Це дозволяє копіювати вставки зовнішніх нечислових рядків. Погуглив і знайшов краще рішення, яке стосується цього @ stackblitz.com/edit/…
vinsinraw

4

Довільна директива RegExp

Ось невелика директива, яка використовує довільний регулярний вираз і блокує користувача для введення недійсного значення

Для маскування лише цифр використовуйте

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

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

3

Просто створіть директиву та додайте нижче провідник хосту:

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

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


Якщо тип запуску з символом char, символ не додаватиметься, але підрахунок довжини моделі займає 1. Як це вирішити ?. Також якщо елемент має максимальну довжину, тоді скопіюйте та вставте змішаний вміст, кількість моделей буде максимальною довжиною. Наприклад, максимальна довжина має 10, тоді скопіюйте та вставте 1238261jhgjh12987 до вводу, додавши лише 123816, але довжина моделі займе 10. Будь-які рішення?
Satheesh Natarajan

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

Ви можете створити цей Валідатор та імпортувати його у свій компонент.
В основному перевіряє вхідний рядок форми:

  • перевірте, що немає крапки
  • перетворює рядок у число
  • check - це ціле число
  • перевірка більше нуля

Щоб реалізувати це у своєму проекті:

  1. запропонований шлях у папці програми: src / app / validators / number.validator.ts
  2. імпортувати у ваш компонент

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

  3. додати його до елемента керування формою
    inputNumber: ['', [NumberValidator.isInteger]],
  4. якщо ви не хочете показувати недійсний символ, прив'яжіть a (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

Ось просте: просте вказівка ​​на подію клавіатури перевіряє довжину ключа один, а ключ не є числом, 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до цієї моделі, змінюючи значення лише на числа:

Як нижче:

EDIT: Додано код для виявлення змін у моделі та оновлення значення вводу

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, символ не додаватиметься, але підрахунок довжини моделі займає 1. Як це вирішити?
Satheesh Natarajan

коли ви перевіряєте довжину, вона залишається 0 в директиві до та після внесення змін. Якщо в якийсь момент це один, він повинен швидко повернутися до 0.
Лахар Шах,

Ні це не так. Просто спробуйте зв'язати numModel.length у шаблоні та перевірити відлік довжини
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();
          }
        };

      }
    }

Директива - це також найкращий спосіб це зробити


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 рішення працює


Будь ласка, використовуйте блоки коду для форматування фрагментів коду.
ЮС

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.