繁体   English   中英

Angular digits only 指令仍然允许写入一些字符

[英]Angular digits only directive still allows some characters to be written

当我在 inte.net 上研究如何最好地执行 digits only 指令时,我发现以下结果接近我自己的解决方案:

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

@Directive({
  selector: '[appOnlyDigits]'
})

export class OnlyDigitsDirective {
  private navigationKeys = [
    'Backspace',
    'Delete',
    'Tab',
    'Escape',
    'Enter',
    'Home',
    'End',
    'ArrowLeft',
    'ArrowRight',
    'Clear',
    'Copy',
    'Paste'
  ];

  inputElement: HTMLElement;

  constructor(public el: ElementRef) {
    this.inputElement = el.nativeElement;
  }

  @HostListener('keydown', ['$event'])
  onKeyDown(e: KeyboardEvent) {
    if (
      this.navigationKeys.indexOf(e.key) > -1 || // Allow: navigation keys: backspace, delete, arrows etc.
      (e.key === 'a' && e.ctrlKey === true) ||   // Allow: Ctrl+A
      (e.key === 'c' && e.ctrlKey === true) ||   // Allow: Ctrl+C
      (e.key === 'v' && e.ctrlKey === true) ||   // Allow: Ctrl+V
      (e.key === 'x' && e.ctrlKey === true) ||   // Allow: Ctrl+X
      (e.key === 'a' && e.metaKey === true) ||   // Allow: Cmd+A (Mac)
      (e.key === 'c' && e.metaKey === true) ||   // Allow: Cmd+C (Mac)
      (e.key === 'v' && e.metaKey === true) ||   // Allow: Cmd+V (Mac)
      (e.key === 'x' && e.metaKey === true)      // Allow: Cmd+X (Mac)
    ) {
      // let it happen, don't do anything.
      return;
    }
    // Ensure that it is a number and stop the keypress.
    if (
      (e.shiftKey || (e.key < '0' || e.key > '9')) &&
      (e.key < 'numpad 0' || e.key > 'numpad 9')
    ) {
      e.preventDefault();
    }
  }

  @HostListener('paste', ['$event'])
  onPaste(event: ClipboardEvent) {
    event.preventDefault();
    const pastedInput: string = event.clipboardData!
      .getData('text/plain')
      .replace(/\D/g, ''); // get a digit-only string
    document.execCommand('insertText', false, pastedInput);
  }

  @HostListener('drop', ['$event'])
  onDrop(event: DragEvent) {
    event.preventDefault();
    const textData = event.dataTransfer!.getData('text').replace(/\D/g, '');
    this.inputElement.focus();
    document.execCommand('insertText', false, textData);
  }
}

但是当我连续按两次 Shift+3 时,它允许输入“^”字符。 有时它还会写“+”字符。

如何在不更改指令结构的情况下解决此问题?

试试这个,我在我正在进行的项目中使用它,效果很好。

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

@Directive({
  selector: '[appNumbersOnly]'
})
export class OnlyNumbersDirective {
  constructor(private el: ElementRef) { }

  @Input() allowMultiLine = false;
  @Input() allowNegative = false;
  @Input() allowDecimal = false;
  @Input() maxLength = 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 = ( window as any).clipboardData && ( window as any).clipboardData.getData('Text') // If IE, use window
      || ( event as ClipboardEvent) && ( event as ClipboardEvent).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) {
      // tslint:disable-next-line: no-eval
      this.regex = ( eval('/^'
        + (this.allowNegative ? '-?' : '')
        + (this.allowDecimal ? '((\\d+\\.?)|(\\.?))\\d*' : '\\d*')
        + '$/g') as RegExp);
    }
    const lines = this.allowMultiLine ? newValue.split('\n') : [newValue];
    for (const line of lines) {
      const lineText = line.replace('\r', '');
      if (this.maxLength && lineText.length > this.maxLength || !lineText.match(this.regex)) {
        event.preventDefault();
        return;
      }
    }
  }

}

虽然我无法重现这一点,但可靠的故障保护是仅对输入值执行替换。 您只需要先将输入元素的类型更改为HTMLInputElement即可。 然后在必要的地方添加替换,一个、两个或所有三个地方:

  inputElement: HTMLInputElement;

  constructor(public el: ElementRef) {
    this.inputElement = el.nativeElement;
  }

  @HostListener('keydown', ['$event'])
  onKeyDown(e: KeyboardEvent) {
    if (
      this.navigationKeys.indexOf(e.key) > -1 || // Allow: navigation keys: backspace, delete, arrows etc.
      (e.key === 'a' && e.ctrlKey === true) || // Allow: Ctrl+A
      (e.key === 'c' && e.ctrlKey === true) || // Allow: Ctrl+C
      (e.key === 'v' && e.ctrlKey === true) || // Allow: Ctrl+V
      (e.key === 'x' && e.ctrlKey === true) || // Allow: Ctrl+X
      (e.key === 'a' && e.metaKey === true) || // Allow: Cmd+A (Mac)
      (e.key === 'c' && e.metaKey === true) || // Allow: Cmd+C (Mac)
      (e.key === 'v' && e.metaKey === true) || // Allow: Cmd+V (Mac)
      (e.key === 'x' && e.metaKey === true) // Allow: Cmd+X (Mac)
    ) {
      // let it happen, don't do anything.
      this.inputElement.value = this.inputElement.value.replace(/\D/g, '');
      return;
    }
    // Ensure that it is a number and stop the keypress.
    if (
      (e.shiftKey || e.key < '0' || e.key > '9') &&
      (e.key < 'numpad 0' || e.key > 'numpad 9')
    ) {
      e.preventDefault();
    }
    this.inputElement.value = this.inputElement.value.replace(/\D/g, '');
  }

  @HostListener('keyup', ['$event'])
  onKeyUp(e: KeyboardEvent) {
    this.inputElement.value = this.inputElement.value.replace(/\D/g, '');
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM