I looked around for Javascript libs that do automatic input formatting for credit card inputs.
The first one was formatter.js which looked promising but it weighs over 6Kb minified and also, when you apply it the placeholder attribute you have on the input disappears.
So, in true software engineering fashion I wrote my own:
function cc_format(value) {
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '')
var matches = v.match(/\d{4,16}/g);
var match = matches && matches[0] || ''
var parts = []
for (i=0, len=match.length; i<len; i+=4) {
parts.push(match.substring(i, i+4))
}
if (parts.length) {
return parts.join(' ')
} else {
return value
}
}
And some tests to prove it:
assert(cc_format('1234') === '1234')
assert(cc_format('123456') === '1234 56')
assert(cc_format('123456789') === '1234 5678 9')
assert(cc_format('') === '')
assert(cc_format('1234 1234 5') === '1234 1234 5')
assert(cc_format('1234 a 1234x 5') === '1234 1234 5')
Comments
Post your own commentwhen i type numbers, the fifth char inserts a space, but the caret places in the fourth position. the sixth char places incorrectly.
just my two cents
I don't understand. What's not working? The fifth input should be preceded by space. I don't see anything there being incorrect.
mmm
when I type in my desktop your demo works Ok.
But, in my celular (htc sense with firefox beta, with hardware keyboard) I have to type FN + number.
When I type '12345' the caret moves to the begining of the '5', so when I type '6' the result is '1234 65'
I see. That's frustrating.
I'll talk to the people who work on that and try to figure out if it's a bug in Firefox or a bug in my code.
I would suggest you apply the formatting on lost focus, because the interaction with the caret is a very hard task. try this on desktop:
1. type "12345678" (the field shows '1234 5678' )
2. place the caret at the begining of field
3. type "12345678" (the field shows '1123 4567 8234 5678' , when I expect '1234 5678' 1234 5678' )
As you can see, the caret changes after the 2nd '1', going to the end of input. This is an unexpected behavior, and a hard problem to solve. You'd have to track current/after caret position. I can't remember if that can be done in javascript.
What about something like onkeyup? I like the idea of changing it as you type because then it's easier to see a long list of strings you've typed in so far.
Surely it must be a bug in Firefox Android that the caret isn't at the end even if the input value is changed in async events.
At least it works on iOS Safari. I just tested that.
This puts sites on my "No Dashes Or Spaces" Hall of Shame at unixwiz.net
That's funny! http://unixwiz.net/ndos-shame.html
I hate when sites can't process the numbers just because the visual presentation is different. For a server to do `.replace(' ', '')` before talking to the gateway is just so incredible trivial.
return value.replace(/\D/g, '').match(/.{1,4}|^$/g).join(' ');
This was the shortest code that I was able to write. I wasn't sure whether \D is an exact alias for [^0-9] but it says so on MDN (you could add a + to improve performance slightly). The |^$ is just one way to work around the otherwise null match for an empty value.
Please check out my demo, which correctly handles the caret. You're gonna love it!
http://jsfiddle.net/jolleekin/aLrp2ftp/
It works on Safari on iOS.
it's working fine..
Shouldn't the length be max of 20 for non standard cards?
Can I use it my projects? What license?
How does it work with different card type? ie AE have different amount of numbers
It doesn't :)
hii i want to print account no like in this format 11-11-111-111
how do i do ?
thanks
Anyone have a patch for this to work with AMEX?
Guys u just change " var matches = v.match(/\d{4,16}/g); " to " var matches = v.match(/\d{4,20}/g);" and it will work with all cards ;)
Here is a better and simpler way.
formatCreditCardNumber(unformattedNumber) {
let pureNumber = unformattedNumber.split(" ").join("");
let pureNumberArray = pureNumber.split("");
let formattedNumberArray = [];
for(let i = 0; i < pureNumberArray.length; i++){
if(!pureNumberArray[i].match(ONLY_DIGITS)){
return;
}
if (i != 0 && i % 4 === 0){
formattedNumberArray.push(" ");
}
formattedNumberArray.push(pureNumberArray[i]);
}
return: formattedNumberArray.join("");
}
ONLY_DIGITS = "^[0-9]*$";
hi
here is a problem with while i am using this code it is working till 4 digits but after fourth digit when it add space then backspace all the code
please give me solution
sorry its my mistake
i was using input type number that's why it removes spaces
Thank you!!
Here is a compact solution with jquery:
$("#card_number").keyup(function() {
var foo = $(this).val().replace(/\s+/g, "").replace(/[^0-9]/gi, ""); // remove non numeric
foo = foo.split(" ").join(""); // remove spaces
if (foo.length > 0) {
foo = foo.match(new RegExp(".{1,4}", "g")).join(" ").slice(-23); // max 23 chars
}
$(this).val(foo);
});
thank you