Angular: How to do Credit Card Input?
Asked Answered
P

2

6

I want to keep input Capacity to 16 numbers and insert space between each set of 4 numbers.

I did a deep search for a input for credit cards that allow user to insert 16 digits and enter a " - " or space between number but all result are for JavaScript and etc. Is there an Angular way to do this? If you have any examples please share.

Pigeontoed answered 18/5, 2018 at 17:14 Comment(1)
If you find one of the offered solutions best, perhaps you can identify it as the solution?Pl
P
3

Loop through the credit card number and manually add spaces

This works in Angular 7+ and probably earlier versions too.

We can just loop through the numbers and add a space every four digits for most Credit Card types, but in a 4-6-5 pattern for American Express.

The only tricky part is handling Backspace and Cursor Position editing (ie if the user clicks inside the input to edit it). If we don't handle this, the loop will make editing the number a weird UX headache.

You can write a custom component or directive for this, but no need to do so if you only have one component in your application that is taking credit card numbers, which is often the case. (Put this code in a directive if you have multiple credit card inputs in your application.)

Here's how I did it inside the payment component in my app:

  • Create a variable called partitions to handle the spacing format. Set it to 4-6-5 for Amex and default to 4-4-4-4 for all other cards. We'll loop through these partitions as we add spaces.
  • Use a template reference variable #ccNumber for cursor position detection.
  • To handle backspace and cursor arrow keys, we store the original cursor position and restore it after editing from a spot anywhere other than the end of the string.
  /* Insert spaces to enhance legibility of credit card numbers */
  creditCardNumberSpacing() {
    const input = this.ccNumberField.nativeElement;
    const { selectionStart } = input;
    const { cardNumber } = this.paymentForm.controls;

    let trimmedCardNum = cardNumber.value.replace(/\s+/g, '');

    if (trimmedCardNum.length > 16) {
      trimmedCardNum = trimmedCardNum.substr(0, 16);
    }

     /* Handle American Express 4-6-5 spacing */
    const partitions = trimmedCardNum.startsWith('34') || trimmedCardNum.startsWith('37') 
                       ? [4,6,5] 
                       : [4,4,4,4];

    const numbers = [];
    let position = 0;
    partitions.forEach(partition => {
      const part = trimmedCardNum.substr(position, partition);
      if (part) numbers.push(part);
      position += partition;
    })

    cardNumber.setValue(numbers.join(' '));

    /* Handle caret position if user edits the number later */
    if (selectionStart < cardNumber.value.length - 1) {
      input.setSelectionRange(selectionStart, selectionStart, 'none');
    }
  }


(If you have a routine of your own to detect American Express numbers, use it. What I'm using here simply examines the first two digits and compares them to PAN/IIN standards.)

Higher in your component, ensure you have the right imports:

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

And:

  @ViewChild('ccNumber') ccNumberField: ElementRef;

And when you set up your form controls, do this so that spaces can be included in your regex pattern:

this.paymentForm = this.fb.group({
  cardNumber: ['', [Validators.required, Validators.pattern('^[ 0-9]*$';), Validators.minLength(17)]]
})

And finally, in your template, configure your element like this:

    <input maxlength="20"
        formControlName="cardNumber"
        type="tel"
        #ccNumber
        (keyup)="creditCardNumberSpacing()">

You should be good to go. Spaces will automatically appear as the user enters their number, and they can still go back and edit if they make typos.

PS: If you want to format with dashes (-) instead of spaces, replace the space with a dash in the cardNumber.setValue(numbers.join(' ')) line, and in the regex adjustment.

Pl answered 18/5, 2020 at 17:53 Comment(0)
A
0

You could create custom form control classes for it.

import { FormControl } from '@angular/forms';

export class CardNumberFormControl extends FormControl{
    setValue(value: string | null, options: any) {
        if(!value){
            super.setValue('', {...options, emitModelToViewChange:true});
            return;
        }
        if(value.match(/[^0-9|\-]/gi)){
            super.setValue(this.value, {...options, emitModelToViewChange: true});
            return;
        }
        if(value.length>19){
            super.setValue(this.value, {...options, emitModelToViewChange:true});
            return;
        }
        if((value.length === 4 && this.value.length === 5) || (value.length === 9 && this.value.length === 10) || (value.length === 14 && this.value.length === 15)){
            super.setValue(value, {...options, emitModelToViewChange: true});
            return;
        }
        if(value.length === 4 || value.length === 9 || value.length === 14){
            super.setValue(value + '-', {...options, emitModelToViewChange: true});
            return;
        }
        super.setValue(value, {...options, emitModelToViewChange: true});
    }
}

Where the final if statement is saying to insert '-' after the 4th character, but you can do every 4th character.

Algol answered 5/5, 2020 at 14:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.