Reputation: 1135
How to format and validate a credit card number with spaces between each 4 digit while typing:
eg: 4464 6846 4354 3564
I have tried:
$('.creditno').keyup(function() {
cc = $(this).val().split("-").join("");
cc = cc.match(new RegExp('.{1,4}$|.{1,4}', 'g')).join("-");
$(this).val(cc);
});
Please help
Upvotes: 30
Views: 85627
Reputation: 1
This is a sample to type only credit card numbers i.e. output will be 4242 4242 4242 4242
.
<input
type="tel" name="credit_card"
id="credit_card_number"
placeholder="Card Number:"
class="form-control"
onkeypress='return formats(this,event)'
onkeyup="return numberValidation(event)"
/>
<script>
function formats(ele,e) {
if(ele.value.length<19) {
ele.value= ele.value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 ');
return true;
} else {
return false;
}
}
function numberValidation(e) {
e.target.value = e.target.value.replace(/[^\d ]/g,'');
return false;
}
</script>
Upvotes: 0
Reputation: 1
This will work. You can just use the formatInput
function from the below example.
import React, { useState } from 'react';
import { TextInput, StyleSheet, View } from 'react-native';
const App: React.FC = () => {
const [formattedValue, setFormattedValue] = useState<string>('');
const formatInput = (text: string) => {
// Remove any non-digit characters
const inputValue = text.replace(/\D/g, '');
// Add a space after every 4 digits
const formattedText = inputValue.replace(/(\d{4})/g, '$1 ');
// Update the state
setFormattedValue(formattedText.trim());
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
keyboardType="numeric"
placeholder="Enter numbers"
value={formattedValue}
onChangeText={(text) => formatInput(text)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
input: {
width: 200,
height: 40,
borderWidth: 1,
padding: 10,
fontSize: 16,
},
});
export default App;
Upvotes: 0
Reputation: 64
If you want to add space every 4 numbers you can user regular expressions and the replace
method. Here's an example
function addSpaceAfterFourNumbers(input) {
// Remove any existing spaces from the input
var strippedInput = input.replace(/\s/g, '');
// Insert a space after every 4 numbers using regular expressions
var formattedInput = strippedInput.replace(/(\d{4})(?=\d)/g, '$1 ');
return formattedInput;
}
// Example usage
var input = '1234567890123456';
var formattedInput = addSpaceAfterFourNumbers(input);
console.log(formattedInput); // Output: 1234 5678 9012 3456
In the above code, the addSpaceAfterFourNumbers()
function takes an input string, removes any existing spaces using the regular expression /\s/g
, and then inserts a space after every 4 numbers using the regular expression (\d{4})(?=\d)
. The $1
in the replace()
method is a backreference to the matched group of four numbers, and the space is added after it.
You can modify the input
variable to test different input strings. The resulting formattedInput
variable will contain the input string with spaces inserted after every 4 numbers.
Upvotes: 1
Reputation: 16
I found everything above never worked so I wrote a new one for fomatting to
0000 0000 0000 0000
//JS credit card formatter for onChange handler
"97181237removed12891237192random3712".replace(/[\D]/g, '').match(/.{1,4}/g)?.join(' ').substring(0, 19) || '';
// '9718 1237 1289 1237'
https://gist.github.com/zakcroft/5c045ebbfa0d3e4aacc4d21fe0196ffa
Upvotes: 0
Reputation: 11
just learned js for 15 days, and encountered the same problem doing a project.
here is my absolutely rubbish solution, it's js only, don't know why even mention that since I don't know what jquery, etc means.
however, it works.
ps: feel free to judge.
const number = document.getElementById("card-number");
//get the new array every time there is
//an input in the field
let listened_number = [];
//put spaces in the array
function number_format(){
listened_number.splice(4,0," ");
listened_number.splice(9,0," ");
listened_number.splice(14,0," ");
}
//"input" type, the function gets activated every time something is entered or deleted.
number.addEventListener("input", e => {
//update the array
listened_number = number.value.replace(/\s+/g,"").split('');
// input caret position before any changes
// 'variable' represents the action to be
//applied on the caret later on
let caret_pos = number.selectionStart;
let variable = 0;
if(e.data === null){
variable = -1;
}else{
variable = 1;
}
// add spaces into the array.
number_format();
// reduced together but trimmed
number.value = listened_number.reduce((pv, cv) => pv + cv).trim();
//!!!!
//because the number.value(content in the input
//field) is reassigned, the input caret will appear
//at the very end, which is not user-friendly at all
//!!!!
switch(caret_pos){
case 5:
setSelection(5 + variable);
break;
case 10:
setSelection(10 + variable);
break;
case 15:
setSelection(15 + variable);
break;
default:
setSelection(caret_pos);
}
})
// set the caret where it supposes to be.
function setSelection(caretPos){
number.setSelectionRange(caretPos,caretPos);
number.focus();
}
<input maxlength="19" id="card-number" type="text" placeholder="e.g. 1234 5678 9123 0000">
it's messy... i know.
Upvotes: 1
Reputation: 840
This will do the job
$('#card-number').on('keypress change blur', function () {
$(this).val(function (index, value) {
var trimValue = value.trim();
var cardDivider = trimValue.replace(/ /g,'').length % 4;
if (trimValue.length < 19 && trimValue !== "") {
if (cardDivider === 0) {
return trimValue + " ";
}
}
return trimValue;
});
});
Upvotes: 0
Reputation: 1
This should work:
var format = [9, 2, 3,5,5,5,5,5,5,5,4, 5, 5, 5, 54, 4, 4, 4, 4, 4, 4,4,4, 4].map((data, index) => {
if ((index + 1) % 4 == 0) {
data = data + " "
}
return data
})
format= format.join("")
console.log("format", format)
Upvotes: 0
Reputation: 1
This should work :
const handleKeyup=(value)=>{
//Remove whitespace
let newValue = value.split(" ").join("")
var format =newValue.split("").map((data, index) => {
if ((index + 1) % 4 == 0) {
data = data + " "
}
return data
})
format= format.join("")
console.log("format", format)}
Upvotes: 0
Reputation: 21
This may simple way:
function numberFormat(x){
return x.replace(/(.{4})/g, "$1 ");
}
If you want to connect dash every 4 digits,
function numberFormat(x){
return x.replace(/(.{4})/g, "$1-");
}
Upvotes: 1
Reputation: 39
You can find here everything about credit card : open source
/*
See on github: https://github.com/muhammederdem/credit-card-form
*/
new Vue({
el: "#app",
data() {
return {
currentCardBackground: Math.floor(Math.random()* 25 + 1), // just for fun :D
cardName: "",
cardNumber: "",
cardMonth: "",
cardYear: "",
cardCvv: "",
minCardYear: new Date().getFullYear(),
amexCardMask: "#### ###### #####",
otherCardMask: "#### #### #### ####",
cardNumberTemp: "",
isCardFlipped: false,
focusElementStyle: null,
isInputFocused: false
};
},
mounted() {
this.cardNumberTemp = this.otherCardMask;
document.getElementById("cardNumber").focus();
},
computed: {
getCardType () {
let number = this.cardNumber;
let re = new RegExp("^4");
if (number.match(re) != null) return "visa";
re = new RegExp("^(34|37)");
if (number.match(re) != null) return "amex";
re = new RegExp("^5[1-5]");
if (number.match(re) != null) return "mastercard";
re = new RegExp("^6011");
if (number.match(re) != null) return "discover";
re = new RegExp('^9792')
if (number.match(re) != null) return 'troy'
return "visa"; // default type
},
generateCardNumberMask () {
return this.getCardType === "amex" ? this.amexCardMask : this.otherCardMask;
},
minCardMonth () {
if (this.cardYear === this.minCardYear) return new Date().getMonth() + 1;
return 1;
}
},
watch: {
cardYear () {
if (this.cardMonth < this.minCardMonth) {
this.cardMonth = "";
}
}
},
methods: {
flipCard (status) {
this.isCardFlipped = status;
},
focusInput (e) {
this.isInputFocused = true;
let targetRef = e.target.dataset.ref;
let target = this.$refs[targetRef];
this.focusElementStyle = {
width: `${target.offsetWidth}px`,
height: `${target.offsetHeight}px`,
transform: `translateX(${target.offsetLeft}px) translateY(${target.offsetTop}px)`
}
},
blurInput() {
let vm = this;
setTimeout(() => {
if (!vm.isInputFocused) {
vm.focusElementStyle = null;
}
}, 300);
vm.isInputFocused = false;
}
}
});
@import url("https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600,700|Source+Sans+Pro:400,600,700&display=swap");
body {
background: #ddeefc;
font-family: "Source Sans Pro", sans-serif;
font-size: 16px;
}
* {
box-sizing: border-box;
}
*:focus {
outline: none;
}
.wrapper {
min-height: 100vh;
display: flex;
padding: 50px 15px;
}
@media screen and (max-width: 700px), (max-height: 500px) {
.wrapper {
flex-wrap: wrap;
flex-direction: column;
}
}
.card-form {
max-width: 570px;
margin: auto;
width: 100%;
}
@media screen and (max-width: 576px) {
.card-form {
margin: 0 auto;
}
}
.card-form__inner {
background: #fff;
box-shadow: 0 30px 60px 0 rgba(90, 116, 148, 0.4);
border-radius: 10px;
padding: 35px;
padding-top: 180px;
}
@media screen and (max-width: 480px) {
.card-form__inner {
padding: 25px;
padding-top: 165px;
}
}
@media screen and (max-width: 360px) {
.card-form__inner {
padding: 15px;
padding-top: 165px;
}
}
.card-form__row {
display: flex;
align-items: flex-start;
}
@media screen and (max-width: 480px) {
.card-form__row {
flex-wrap: wrap;
}
}
.card-form__col {
flex: auto;
margin-right: 35px;
}
.card-form__col:last-child {
margin-right: 0;
}
@media screen and (max-width: 480px) {
.card-form__col {
margin-right: 0;
flex: unset;
width: 100%;
margin-bottom: 20px;
}
.card-form__col:last-child {
margin-bottom: 0;
}
}
.card-form__col.-cvv {
max-width: 150px;
}
@media screen and (max-width: 480px) {
.card-form__col.-cvv {
max-width: initial;
}
}
.card-form__group {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
}
.card-form__group .card-input__input {
flex: 1;
margin-right: 15px;
}
.card-form__group .card-input__input:last-child {
margin-right: 0;
}
.card-form__button {
width: 100%;
height: 55px;
background: #2364d2;
border: none;
border-radius: 5px;
font-size: 22px;
font-weight: 500;
font-family: "Source Sans Pro", sans-serif;
box-shadow: 3px 10px 20px 0px rgba(35, 100, 210, 0.3);
color: #fff;
margin-top: 20px;
cursor: pointer;
}
@media screen and (max-width: 480px) {
.card-form__button {
margin-top: 10px;
}
}
.card-item {
max-width: 430px;
height: 270px;
margin-left: auto;
margin-right: auto;
position: relative;
z-index: 2;
width: 100%;
}
@media screen and (max-width: 480px) {
.card-item {
max-width: 310px;
height: 220px;
width: 90%;
}
}
@media screen and (max-width: 360px) {
.card-item {
height: 180px;
}
}
.card-item.-active .card-item__side.-front {
transform: perspective(1000px) rotateY(180deg) rotateX(0deg) rotateZ(0deg);
}
.card-item.-active .card-item__side.-back {
transform: perspective(1000px) rotateY(0) rotateX(0deg) rotateZ(0deg);
}
.card-item__focus {
position: absolute;
z-index: 3;
border-radius: 5px;
left: 0;
top: 0;
width: 100%;
height: 100%;
transition: all 0.35s cubic-bezier(0.71, 0.03, 0.56, 0.85);
opacity: 0;
pointer-events: none;
overflow: hidden;
border: 2px solid rgba(255, 255, 255, 0.65);
}
.card-item__focus:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
background: #08142f;
height: 100%;
border-radius: 5px;
filter: blur(25px);
opacity: 0.5;
}
.card-item__focus.-active {
opacity: 1;
}
.card-item__side {
border-radius: 15px;
overflow: hidden;
box-shadow: 0 20px 60px 0 rgba(14, 42, 90, 0.55);
transform: perspective(2000px) rotateY(0deg) rotateX(0deg) rotate(0deg);
transform-style: preserve-3d;
transition: all 0.8s cubic-bezier(0.71, 0.03, 0.56, 0.85);
backface-visibility: hidden;
height: 100%;
}
.card-item__side.-back {
position: absolute;
top: 0;
left: 0;
width: 100%;
transform: perspective(2000px) rotateY(-180deg) rotateX(0deg) rotate(0deg);
z-index: 2;
padding: 0;
height: 100%;
}
.card-item__side.-back .card-item__cover {
transform: rotateY(-180deg);
}
.card-item__bg {
max-width: 100%;
display: block;
max-height: 100%;
height: 100%;
width: 100%;
object-fit: cover;
}
.card-item__cover {
height: 100%;
background-color: #1c1d27;
position: absolute;
height: 100%;
background-color: #1c1d27;
left: 0;
top: 0;
width: 100%;
border-radius: 15px;
overflow: hidden;
}
.card-item__cover:after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(6, 2, 29, 0.45);
}
.card-item__top {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 40px;
padding: 0 10px;
}
@media screen and (max-width: 480px) {
.card-item__top {
margin-bottom: 25px;
}
}
@media screen and (max-width: 360px) {
.card-item__top {
margin-bottom: 15px;
}
}
.card-item__chip {
width: 60px;
}
@media screen and (max-width: 480px) {
.card-item__chip {
width: 50px;
}
}
@media screen and (max-width: 360px) {
.card-item__chip {
width: 40px;
}
}
.card-item__type {
height: 45px;
position: relative;
display: flex;
justify-content: flex-end;
max-width: 100px;
margin-left: auto;
width: 100%;
}
@media screen and (max-width: 480px) {
.card-item__type {
height: 40px;
max-width: 90px;
}
}
@media screen and (max-width: 360px) {
.card-item__type {
height: 30px;
}
}
.card-item__typeImg {
max-width: 100%;
object-fit: contain;
max-height: 100%;
object-position: top right;
}
.card-item__info {
color: #fff;
width: 100%;
max-width: calc(100% - 85px);
padding: 10px 15px;
font-weight: 500;
display: block;
cursor: pointer;
}
@media screen and (max-width: 480px) {
.card-item__info {
padding: 10px;
}
}
.card-item__holder {
opacity: 0.7;
font-size: 13px;
margin-bottom: 6px;
}
@media screen and (max-width: 480px) {
.card-item__holder {
font-size: 12px;
margin-bottom: 5px;
}
}
.card-item__wrapper {
font-family: "Source Code Pro", monospace;
padding: 25px 15px;
position: relative;
z-index: 4;
height: 100%;
text-shadow: 7px 6px 10px rgba(14, 42, 90, 0.8);
user-select: none;
}
@media screen and (max-width: 480px) {
.card-item__wrapper {
padding: 20px 10px;
}
}
.card-item__name {
font-size: 18px;
line-height: 1;
white-space: nowrap;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
text-transform: uppercase;
}
@media screen and (max-width: 480px) {
.card-item__name {
font-size: 16px;
}
}
.card-item__nameItem {
display: inline-block;
min-width: 8px;
position: relative;
}
.card-item__number {
font-weight: 500;
line-height: 1;
color: #fff;
font-size: 27px;
margin-bottom: 35px;
display: inline-block;
padding: 10px 15px;
cursor: pointer;
}
@media screen and (max-width: 480px) {
.card-item__number {
font-size: 21px;
margin-bottom: 15px;
padding: 10px 10px;
}
}
@media screen and (max-width: 360px) {
.card-item__number {
font-size: 19px;
margin-bottom: 10px;
padding: 10px 10px;
}
}
.card-item__numberItem {
width: 16px;
display: inline-block;
}
.card-item__numberItem.-active {
width: 30px;
}
@media screen and (max-width: 480px) {
.card-item__numberItem {
width: 13px;
}
.card-item__numberItem.-active {
width: 16px;
}
}
@media screen and (max-width: 360px) {
.card-item__numberItem {
width: 12px;
}
.card-item__numberItem.-active {
width: 8px;
}
}
.card-item__content {
color: #fff;
display: flex;
align-items: flex-start;
}
.card-item__date {
flex-wrap: wrap;
font-size: 18px;
margin-left: auto;
padding: 10px;
display: inline-flex;
width: 80px;
white-space: nowrap;
flex-shrink: 0;
cursor: pointer;
}
@media screen and (max-width: 480px) {
.card-item__date {
font-size: 16px;
}
}
.card-item__dateItem {
position: relative;
}
.card-item__dateItem span {
width: 22px;
display: inline-block;
}
.card-item__dateTitle {
opacity: 0.7;
font-size: 13px;
padding-bottom: 6px;
width: 100%;
}
@media screen and (max-width: 480px) {
.card-item__dateTitle {
font-size: 12px;
padding-bottom: 5px;
}
}
.card-item__band {
background: rgba(0, 0, 19, 0.8);
width: 100%;
height: 50px;
margin-top: 30px;
position: relative;
z-index: 2;
}
@media screen and (max-width: 480px) {
.card-item__band {
margin-top: 20px;
}
}
@media screen and (max-width: 360px) {
.card-item__band {
height: 40px;
margin-top: 10px;
}
}
.card-item__cvv {
text-align: right;
position: relative;
z-index: 2;
padding: 15px;
}
.card-item__cvv .card-item__type {
opacity: 0.7;
}
@media screen and (max-width: 360px) {
.card-item__cvv {
padding: 10px 15px;
}
}
.card-item__cvvTitle {
padding-right: 10px;
font-size: 15px;
font-weight: 500;
color: #fff;
margin-bottom: 5px;
}
.card-item__cvvBand {
height: 45px;
background: #fff;
margin-bottom: 30px;
text-align: right;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 10px;
color: #1a3b5d;
font-size: 18px;
border-radius: 4px;
box-shadow: 0px 10px 20px -7px rgba(32, 56, 117, 0.35);
}
@media screen and (max-width: 480px) {
.card-item__cvvBand {
height: 40px;
margin-bottom: 20px;
}
}
@media screen and (max-width: 360px) {
.card-item__cvvBand {
margin-bottom: 15px;
}
}
.card-list {
margin-bottom: -130px;
}
@media screen and (max-width: 480px) {
.card-list {
margin-bottom: -120px;
}
}
.card-input {
margin-bottom: 20px;
}
.card-input__label {
font-size: 14px;
margin-bottom: 5px;
font-weight: 500;
color: #1a3b5d;
width: 100%;
display: block;
user-select: none;
}
.card-input__input {
width: 100%;
height: 50px;
border-radius: 5px;
box-shadow: none;
border: 1px solid #ced6e0;
transition: all 0.3s ease-in-out;
font-size: 18px;
padding: 5px 15px;
background: none;
color: #1a3b5d;
font-family: "Source Sans Pro", sans-serif;
}
.card-input__input:hover, .card-input__input:focus {
border-color: #3d9cff;
}
.card-input__input:focus {
box-shadow: 0px 10px 20px -13px rgba(32, 56, 117, 0.35);
}
.card-input__input.-select {
-webkit-appearance: none;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAeCAYAAABuUU38AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUxJREFUeNrM1sEJwkAQBdCsngXPHsQO9O5FS7AAMVYgdqAd2IGCDWgFnryLFQiCZ8EGnJUNimiyM/tnk4HNEAg/8y6ZmMRVqz9eUJvRaSbvutCZ347bXVJy/ZnvTmdJ862Me+hAbZCTs6GHpyUi1tTSvPnqTpoWZPUa7W7ncT3vK4h4zVejy8QzM3WhVUO8ykI6jOxoGA4ig3BLHcNFSCGqGAkig2yqgpEiMsjSfY9LxYQg7L6r0X6wS29YJiYQYecemY+wHrXD1+bklGhpAhBDeu/JfIVGxaAQ9sb8CI+CQSJ+QmJg0Ii/EE2MBiIXooHRQhRCkBhNhBcEhLkwf05ZCG8ICCOpk0MULmvDSY2M8UawIRExLIQIEgHDRoghihgRIgiigBEjgiFATBACAgFgghEwSAAGgoBCBBgYAg5hYKAIFYgHBo6w9RRgAFfy160QuV8NAAAAAElFTkSuQmCC");
background-size: 12px;
background-position: 90% center;
background-repeat: no-repeat;
padding-right: 30px;
}
.slide-fade-up-enter-active {
transition: all 0.25s ease-in-out;
transition-delay: 0.1s;
position: relative;
}
.slide-fade-up-leave-active {
transition: all 0.25s ease-in-out;
position: absolute;
}
.slide-fade-up-enter {
opacity: 0;
transform: translateY(15px);
pointer-events: none;
}
.slide-fade-up-leave-to {
opacity: 0;
transform: translateY(-15px);
pointer-events: none;
}
.slide-fade-right-enter-active {
transition: all 0.25s ease-in-out;
transition-delay: 0.1s;
position: relative;
}
.slide-fade-right-leave-active {
transition: all 0.25s ease-in-out;
position: absolute;
}
.slide-fade-right-enter {
opacity: 0;
transform: translateX(10px) rotate(45deg);
pointer-events: none;
}
.slide-fade-right-leave-to {
opacity: 0;
transform: translateX(-10px) rotate(45deg);
pointer-events: none;
}
.github-btn {
position: absolute;
right: 40px;
bottom: 50px;
text-decoration: none;
padding: 15px 25px;
border-radius: 4px;
box-shadow: 0px 4px 30px -6px rgba(36, 52, 70, 0.65);
background: #24292e;
color: #fff;
font-weight: bold;
letter-spacing: 1px;
font-size: 16px;
text-align: center;
transition: all 0.3s ease-in-out;
}
@media screen and (min-width: 500px) {
.github-btn:hover {
transform: scale(1.1);
box-shadow: 0px 17px 20px -6px rgba(36, 52, 70, 0.36);
}
}
@media screen and (max-width: 700px) {
.github-btn {
position: relative;
bottom: auto;
right: auto;
margin-top: 20px;
}
.github-btn:active {
transform: scale(1.1);
box-shadow: 0px 17px 20px -6px rgba(36, 52, 70, 0.36);
}
}
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div class="wrapper" id="app">
<div class="card-form">
<div class="card-list">
<div class="card-item" v-bind:class="{ '-active' : isCardFlipped }">
<div class="card-item__side -front">
<div class="card-item__focus" v-bind:class="{'-active' : focusElementStyle }" v-bind:style="focusElementStyle" ref="focusElement"></div>
<div class="card-item__cover">
<img
v-bind:src="'https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/' + currentCardBackground + '.jpeg'" class="card-item__bg">
</div>
<div class="card-item__wrapper">
<div class="card-item__top">
<img src="https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/chip.png" class="card-item__chip">
<div class="card-item__type">
<transition name="slide-fade-up">
<img v-bind:src="'https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/' + getCardType + '.png'" v-if="getCardType" v-bind:key="getCardType" alt="" class="card-item__typeImg">
</transition>
</div>
</div>
<label for="cardNumber" class="card-item__number" ref="cardNumber">
<template v-if="getCardType === 'amex'">
<span v-for="(n, $index) in amexCardMask" :key="$index">
<transition name="slide-fade-up">
<div
class="card-item__numberItem"
v-if="$index > 4 && $index < 14 && cardNumber.length > $index && n.trim() !== ''"
>*</div>
<div class="card-item__numberItem"
:class="{ '-active' : n.trim() === '' }"
:key="$index" v-else-if="cardNumber.length > $index">
{{cardNumber[$index]}}
</div>
<div
class="card-item__numberItem"
:class="{ '-active' : n.trim() === '' }"
v-else
:key="$index + 1"
>{{n}}</div>
</transition>
</span>
</template>
<template v-else>
<span v-for="(n, $index) in otherCardMask" :key="$index">
<transition name="slide-fade-up">
<div
class="card-item__numberItem"
v-if="$index > 4 && $index < 15 && cardNumber.length > $index && n.trim() !== ''"
>*</div>
<div class="card-item__numberItem"
:class="{ '-active' : n.trim() === '' }"
:key="$index" v-else-if="cardNumber.length > $index">
{{cardNumber[$index]}}
</div>
<div
class="card-item__numberItem"
:class="{ '-active' : n.trim() === '' }"
v-else
:key="$index + 1"
>{{n}}</div>
</transition>
</span>
</template>
</label>
<div class="card-item__content">
<label for="cardName" class="card-item__info" ref="cardName">
<div class="card-item__holder">Card Holder</div>
<transition name="slide-fade-up">
<div class="card-item__name" v-if="cardName.length" key="1">
<transition-group name="slide-fade-right">
<span class="card-item__nameItem" v-for="(n, $index) in cardName.replace(/\s\s+/g, ' ')" v-if="$index === $index" v-bind:key="$index + 1">{{n}}</span>
</transition-group>
</div>
<div class="card-item__name" v-else key="2">Full Name</div>
</transition>
</label>
<div class="card-item__date" ref="cardDate">
<label for="cardMonth" class="card-item__dateTitle">Expires</label>
<label for="cardMonth" class="card-item__dateItem">
<transition name="slide-fade-up">
<span v-if="cardMonth" v-bind:key="cardMonth">{{cardMonth}}</span>
<span v-else key="2">MM</span>
</transition>
</label>
/
<label for="cardYear" class="card-item__dateItem">
<transition name="slide-fade-up">
<span v-if="cardYear" v-bind:key="cardYear">{{String(cardYear).slice(2,4)}}</span>
<span v-else key="2">YY</span>
</transition>
</label>
</div>
</div>
</div>
</div>
<div class="card-item__side -back">
<div class="card-item__cover">
<img
v-bind:src="'https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/' + currentCardBackground + '.jpeg'" class="card-item__bg">
</div>
<div class="card-item__band"></div>
<div class="card-item__cvv">
<div class="card-item__cvvTitle">CVV</div>
<div class="card-item__cvvBand">
<span v-for="(n, $index) in cardCvv" :key="$index">
*
</span>
</div>
<div class="card-item__type">
<img v-bind:src="'https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/' + getCardType + '.png'" v-if="getCardType" class="card-item__typeImg">
</div>
</div>
</div>
</div>
</div>
<div class="card-form__inner">
<div class="card-input">
<label for="cardNumber" class="card-input__label">Card Number</label>
<input type="text" id="cardNumber" class="card-input__input" v-mask="generateCardNumberMask" v-model="cardNumber" v-on:focus="focusInput" v-on:blur="blurInput" data-ref="cardNumber" autocomplete="off">
</div>
<div class="card-input">
<label for="cardName" class="card-input__label">Card Holders</label>
<input type="text" id="cardName" class="card-input__input" v-model="cardName" v-on:focus="focusInput" v-on:blur="blurInput" data-ref="cardName" autocomplete="off">
</div>
<div class="card-form__row">
<div class="card-form__col">
<div class="card-form__group">
<label for="cardMonth" class="card-input__label">Expiration Date</label>
<select class="card-input__input -select" id="cardMonth" v-model="cardMonth" v-on:focus="focusInput" v-on:blur="blurInput" data-ref="cardDate">
<option value="" disabled selected>Month</option>
<option v-bind:value="n < 10 ? '0' + n : n" v-for="n in 12" v-bind:disabled="n < minCardMonth" v-bind:key="n">
{{n < 10 ? '0' + n : n}}
</option>
</select>
<select class="card-input__input -select" id="cardYear" v-model="cardYear" v-on:focus="focusInput" v-on:blur="blurInput" data-ref="cardDate">
<option value="" disabled selected>Year</option>
<option v-bind:value="$index + minCardYear" v-for="(n, $index) in 12" v-bind:key="n">
{{$index + minCardYear}}
</option>
</select>
</div>
</div>
<div class="card-form__col -cvv">
<div class="card-input">
<label for="cardCvv" class="card-input__label">CVV</label>
<input type="text" class="card-input__input" id="cardCvv" v-mask="'####'" maxlength="4" v-model="cardCvv" v-on:focus="flipCard(true)" v-on:blur="flipCard(false)" autocomplete="off">
</div>
</div>
</div>
<button class="card-form__button">
Submit
</button>
</div>
</div>
</div>
Upvotes: 0
Reputation: 1
Let's try this. This code will replace your edit number in real-time.
$(document).ready(function() {
document.getElementById('card_no').onkeyup = function (e) {
if (this.value == this.lastValue) return;
var caretPosition = this.selectionStart;
var sanitizedValue = this.value.replace(/[^0-9]/gi, '');
var parts = [];
for (var i = 0, len = sanitizedValue.length; i < len; i += 4) {
parts.push(sanitizedValue.substring(i, i + 4));
}
for (var i = caretPosition - 1; i >= 0; i--) {
var c = this.value[i];
if (c < '0' || c > '9') {
caretPosition--;
}
}
caretPosition += Math.floor(caretPosition / 4);
this.value = this.lastValue = parts.join(' ');
this.selectionStart = this.selectionEnd = caretPosition;
}
});
Upvotes: 0
Reputation: 1402
export const removeNonNumber = (string = "") => string.replace(/[^\d]/g, "");
export const removeLeadingSpaces = (string = "") => string.replace(/^\s+/g, "");
const limitLength = (string = "", maxLength) => string.substr(0, maxLength);
const FALLBACK_CARD = { gaps: [4, 8, 12], lengths: [16], code: { size: 3 } };
const addGaps = (string = "", gaps) => {
const offsets = [0].concat(gaps).concat([string.length]);
return offsets
.map((end, index) => {
if (index === 0) return "";
const start = offsets[index - 1];
return string.substr(start, end - start);
})
.filter((part) => part !== "")
.join(" ");
};
//this method to call
_formatNumber = (number, card) => {
const numberSanitized = removeNonNumber(number);
const maxLength = card.lengths[card.lengths.length - 1];
const lengthSanitized = limitLength(numberSanitized, maxLength);
const formatted = addGaps(lengthSanitized, card.gaps);
//set your state here
return formatted;
};
//use above method like this in text input
cardEnter(strings = "") {
this._formatNumber(strings, FALLBACK_CARD);
}
Upvotes: 0
Reputation: 221
With ES6
export const formatCardNumber = value => {
const regex = /^(\d{0,4})(\d{0,4})(\d{0,4})(\d{0,4})$/g
const onlyNumbers = value.replace(/[^\d]/g, '')
return onlyNumbers.replace(regex, (regex, $1, $2, $3, $4) =>
[$1, $2, $3, $4].filter(group => !!group).join(' ')
)
}
Upvotes: 16
Reputation: 370
Format credit card number will be 16 digits and having automatic spacing between them will get by trying the below code for me. try it once
handlecard(text) {
let formattedText = text.split(' ').join('');
if (formattedText.length <= 16) {
if (formattedText.length > 0) {
formattedText = formattedText.match(new RegExp('.{1,4}', 'g')).join(' ');
}
} else {
alert("plz stop here")
}
this.setState({ creditCard: formattedText });
return formattedText;
}
Upvotes: -1
Reputation: 665
using vanilla js
javascript:
function formatCreditCardOnKey(event) {
//on keyup, check for backspace to skip processing
var code = (event.which) ? event.which : event.keyCode;
if(code != 8)
formatCreditCard();
else{
//trim whitespace from end; trimEnd() doesn't work in IE
document.getElementById("cardNumber").value = document.getElementById("cardNumber").value.replace(/\s+$/, '');
}
}
function formatCreditCard() {
var cardField = document.getElementById("cardNumber");
//remove all non-numeric characters
var realNumber = cardField.value.replace(/\D/g,'');
var newNumber = "";
for(var x = 1; x <= realNumber.length; x++){
//make sure input is a digit
if (isNumeric(realNumber.charAt(x-1)))
newNumber += realNumber.charAt(x-1);
//add space every 4 numeric digits
if(x % 4 == 0 && x > 0 && x < 15)
newNumber += " ";
}
cardField.value = newNumber;
}
function isNumeric(char){
return('0123456789'.indexOf(char) !== -1);
}
HTML:
<input type="text" id="cardNumber" maxlength="19" onKeyUp="formatCreditCardOnKey(event)" onBlur="formatCreditCard()" onFocus="formatCreditCard()"/>
This works (for me) with autofill, allows the user to use backspace as expected (they don't have to delete whitespace), and doesn't allow (other) non-numeric characters.
Upvotes: 2
Reputation: 196
Just wrote this to handle Visa, Discover, Master Card and Amex (with formatting and card type identification).
// SAMPLE FIELD: <input type="text" name="cstCCNumber" id="cstCCNumber" value=""onkeyup="cc_format('cstCCNumber','cstCCardType');">
function cc_format(ccid,ctid) {
// supports Amex, Master Card, Visa, and Discover
// parameter 1 ccid= id of credit card number field
// parameter 2 ctid= id of credit card type field
var ccNumString=document.getElementById(ccid).value;
ccNumString=ccNumString.replace(/[^0-9]/g, '');
// mc, starts with - 51 to 55
// v, starts with - 4
// dsc, starts with 6011, 622126-622925, 644-649, 65
// amex, starts with 34 or 37
var typeCheck = ccNumString.substring(0, 2);
var cType='';
var block1='';
var block2='';
var block3='';
var block4='';
var formatted='';
if (typeCheck.length==2) {
typeCheck=parseInt(typeCheck);
if (typeCheck >= 40 && typeCheck <= 49) {
cType='Visa';
}
else if (typeCheck >= 51 && typeCheck <= 55) {
cType='Master Card';
}
else if ((typeCheck >= 60 && typeCheck <= 62) || (typeCheck == 64) || (typeCheck == 65)) {
cType='Discover';
}
else if (typeCheck==34 || typeCheck==37) {
cType='American Express';
}
else {
cType='Invalid';
}
}
// all support card types have a 4 digit firt block
block1 = ccNumString.substring(0, 4);
if (block1.length==4) {
block1=block1 + ' ';
}
if (cType == 'Visa' || cType == 'Master Card' || cType == 'Discover') {
// for 4X4 cards
block2 = ccNumString.substring(4, 8);
if (block2.length==4) {
block2=block2 + ' ';
}
block3 = ccNumString.substring(8, 12);
if (block3.length==4) {
block3=block3 + ' ';
}
block4 = ccNumString.substring(12, 16);
}
else if (cType == 'American Express') {
// for Amex cards
block2 = ccNumString.substring(4, 10);
if (block2.length==6) {
block2=block2 + ' ';
}
block3 = ccNumString.substring(10, 15);
block4='';
}
else if (cType == 'Invalid') {
// for Amex cards
block1 = typeCheck;
block2='';
block3='';
block4='';
alert('Invalid Card Number');
}
formatted=block1 + block2 + block3 + block4;
document.getElementById(ccid).value=formatted;
document.getElementById(ctid).value=cType;
}
Upvotes: 16
Reputation: 2190
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
}
}
onload = function() {
document.getElementById('cc').oninput = function() {
this.value = cc_format(this.value)
}
}
function checkDigit(event) {
var code = (event.which) ? event.which : event.keyCode;
if ((code < 48 || code > 57) && (code > 31)) {
return false;
}
return true;
}
<form>
<input id="cc" value="" placeholder="1234 1234 1234 1234" onkeypress="return checkDigit(event)">
</form>
Live demo of check digit and formatting of CC card number
Upvotes: 5
Reputation: 5876
I couldn't find a reasonable solution that works with text editing, so here you go:
$("#cardNumber").on("keydown", function(e) {
var cursor = this.selectionStart;
if (this.selectionEnd != cursor) return;
if (e.which == 46) {
if (this.value[cursor] == " ") this.selectionStart++;
} else if (e.which == 8) {
if (cursor && this.value[cursor - 1] == " ") this.selectionEnd--;
}
}).on("input", function() {
var value = this.value;
var cursor = this.selectionStart;
var matches = value.substring(0, cursor).match(/[^0-9]/g);
if (matches) cursor -= matches.length;
value = value.replace(/[^0-9]/g, "").substring(0, 16);
var formatted = "";
for (var i=0, n=value.length; i<n; i++) {
if (i && i % 4 == 0) {
if (formatted.length <= cursor) cursor++;
formatted += " ";
}
formatted += value[i];
}
if (formatted == this.value) return;
this.value = formatted;
this.selectionEnd = cursor;
});
The keydown
listener is needed to adjust the cursor position for backspace and delete to move past spaces. It should not be used to restrict character entry, as you don't want to use key codes for that.
The input
listener rebuilds the text, strips non-numbers, adds spaces every 4 characters, and preserves the cursor position.
Upvotes: 11
Reputation: 405
Find
using angularjs directive. Format Card Numbers in xxxxxxxxxxxx3456 Fromat.
angular.module('myApp', [])
.directive('maskInput', function() {
return {
require: "ngModel",
restrict: "AE",
scope: {
ngModel: '=',
},
link: function(scope, elem, attrs) {
var orig = scope.ngModel;
var edited = orig;
scope.ngModel = edited.slice(4).replace(/\d/g, 'x') + edited.slice(-4);
elem.bind("blur", function() {
var temp;
orig = elem.val();
temp = elem.val();
elem.val(temp.slice(4).replace(/\d/g, 'x') + temp.slice(-4));
});
elem.bind("focus", function() {
elem.val(orig);
});
}
};
})
.controller('myCtrl', ['$scope', '$interval', function($scope, $interval) {
$scope.creditCardNumber = "1234567890123456";
}]);
Upvotes: 2
Reputation: 3986
Try this:
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
}
}
Note: Check this for detailed information https://www.peterbe.com/plog/cc-formatter.
To restrict the user to enter number only:
Javascript Way
<input type="text" id="txt_cardNumber" name="txt_cardNumber" onkeypress="return checkDigit(event)">
function checkDigit(event) {
var code = (event.which) ? event.which : event.keyCode;
if ((code < 48 || code > 57) && (code > 31)) {
return false;
}
return true;
}
OR
function checkDigit() {
var allowedChars = "0123456789";
var entryVal = document.getElementById('txt_cardNumber').value();
var flag;
for(var i=0; i<entryVal.length; i++){
flag = false;
for(var j=0; j<allowedChars.length; j++){
if(entryVal.charAt(i) == allowedChars.charAt(j)) {
flag = true;
}
}
if(flag == false) {
entryVal = entryVal.replace(entryVal.charAt(i),""); i--;
}
}
return true;
}
HTML5 Way
<input type="text" id="txt_cardNumber" name="txt_cardNumber" pattern="[0-9.]+">
<input type="number" id="txt_cardNumber" name="txt_cardNumber">
jQuery Way
$("#txt_cardNumber").keypress(function (e) {
if ((e.which < 48 || e.which > 57) && (e.which !== 8) && (e.which !== 0)) {
return false;
}
return true;
});
Note: Please check here to get more information about various key code.
Upvotes: 50
Reputation: 44
function testCreditCard () {
myCardNo = document.getElementById('CardNumber').value;
myCardType = document.getElementById('CardType').value;
if (checkCreditCard (myCardNo,myCardType)) {
alert ("Credit card has a valid format")
}
else {alert (ccErrors[ccErrorNo])};
}
check this link for lib http://www.braemoor.co.uk/software/creditcard.shtml
Upvotes: 1
Reputation: 3497
<?php
function luhn_check($number) {
// Strip any non-digits (useful for credit card numbers with spaces and hyphens)
$number=preg_replace('/\D/', '', $number);
// Set the string length and parity
$number_length=strlen($number);
$parity=$number_length % 2;
// Loop through each digit and do the maths
$total=0;
for ($i=0; $i<$number_length; $i++) {
$digit=$number[$i];
// Multiply alternate digits by two
if ($i % 2 == $parity) {
$digit*=2;
// If the sum is two digits, add them together (in effect)
if ($digit > 9) {
$digit-=9;
}
}
// Total up the digits
$total+=$digit;
}
// If the total mod 10 equals 0, the number is valid
return ($total % 10 == 0) ? TRUE : FALSE;
}
?>
Upvotes: 1