mevr
mevr

Reputation: 1135

Format credit card number

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

Answers (22)

adil rehman
adil rehman

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

Celina Singh
Celina Singh

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

aries
aries

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

Zebadix
Zebadix

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

DaY
DaY

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

cross_flame
cross_flame

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

Erisan AKOREDE
Erisan AKOREDE

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

Erisan AKOREDE
Erisan AKOREDE

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

AstonishGong
AstonishGong

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

KING-CODE
KING-CODE

Reputation: 39

You can find here everything about credit card : open source

open source here (:

/*
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

Nguyen Tung
Nguyen Tung

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

Antier Solutions
Antier Solutions

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

Juliano Reis
Juliano Reis

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

ravi
ravi

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

Russell Chisholm
Russell Chisholm

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

Robert H
Robert H

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

Gauravbhai Daxini
Gauravbhai Daxini

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

NateS
NateS

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

Sagar Bhosale
Sagar Bhosale

Reputation: 405

Find

Plunker for Formatting Credit Card Numbers

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

prava
prava

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

Bhanu
Bhanu

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

Waruna Manjula
Waruna Manjula

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

Related Questions