简体   繁体   中英

Making a 4 digit pin in Angular 2/4 for mobile phones?

What have others done for a 4 digit pin? I am looking to make a 4 digit pin in Angular 2/4 but there seems to be no easy way to do it, that I have found out yet.

Phones do have a soft keyboard that can show only numbers. The best way (only way) to show a number keyboard on both android and ios is with the following html tag:

<input
    type="number" 
    pattern="[0-9]*" 
    inputmode="numeric" 
    style="-webkit-text-security: disc;"></input>

Now that gives me a keyboard that has decimals, dashes, commas, among other things. I need to make sure only numbers are put in the box. The best way I can think of is catch key press events and remove invalid characters as they are typed. There are 3 different ways I have tried and all have flaws: First is catch the keyup event:

The Html:

<input
    (keyup)="checkPin($event)" 
    type="number" 
    pattern="[0-9]*" 
    inputmode="numeric" 
    style="-webkit-text-security: disc;"></input>

The Typescript:

checkPin($event: KeyboardEvent) {
  console.log($event)
  let value = (<HTMLInputElement>event.target).value;

  if ($event.target) {
    if (value == "") {
      value = value.slice(0, 0);
    }

    if (value.length > 4) {
      value = value.slice(0, 4)
    }
    (<HTMLInputElement>event.target).value = value.replace(/\D/g, '');
  }
}

I do not like this because code because as the key is pushed it can be seen in the box then disappears.

The second approach is to catch the keypress event:

The HTML:

<input 
  (keypress)="keyPress($event)"
  type="number"
  pattern="[0-9]*"
  inputmode="numeric"
  style="-webkit-text-security: disc;"></input>

The Type Script

keyPress(event: any) {
  const pattern = /[0-9]/;
  const inputChar = String.fromCharCode(event.charCode);
  let lIsTooLong: boolean = event.target.value.length > 3
  if (!pattern.test(inputChar) ||  lIsTooLong) {
    // invalid character, prevent input
    event.preventDefault();
  }
}

This works very well, but it does not work on android when the period or comma is pushed, the period is still put into the input box.

I tried using input :

The HTML:

<input 
  #myInput
  [(ngModel)]="input"
  (input)="myInput.value = format(input)"
  type="number"
  pattern="[0-9]*"
  inputmode="numeric"
  style="-webkit-text-security: disc;"></input>

The Type Script:

format(valString) {
  console.log(valString);
  if (!valString) {
    return '';
  }
  let val = valString.toString();
  if (val.length > 4) {
    val = val.slice(0, 4)
  }
  return val.replace(/\D+/g, '')
}

This last way seemed promising but when more than two . were entered the code actually broke and stopped calling the format function. I did a console log and the value valString was and empty string, but the text in the box was 123423.........

UPDATE :

There is an easier way. Using what you originaly used, keyup event:

HTML :

<input type="number" style="border:1px solid black" (keydown)="onKeyPress($event)" >

Typescript :

onKeyPress(event){
  if (!(event.keyCode >= 48 && event.keyCode <= 57)){
        event.preventDefault()
  }
}

DEMO


The input could be processed thru (input) event where you remove anything not numeric with a regexp. But this method will need two-way binding mechanism. Example:

HTML :

   <input type="number" [(ngModel)]="input" #myInput style="border:1px solid black" (input)="myInput.value = format(input)">

Typescript :

format(valString) {
    if (!valString) {
        return '';
    }
    let val = valString.toString();
    return val.replace(/\D+/g, '');
}

DEMO

What you're trying to do is best done using a custom directive

The following steps should help you solve your problem:

Generate a new custom directive: ng generate directive numberInput

Then in the generated directive class add this:

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

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

  constructor(private el: ElementRef) { }

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

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

}
  }

Then within your template add:

<input type="text" name="pin" id="pin" placeholder="000" maxlength="4" inputmode="numeric" pattern="[0-9]*" digitOnly>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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