plb_ba
Last Updated: February 25, 2016
·
1.232K
· irichlau

dynamic credit card form with javascript. no jquery.

This is my first time working in javascript at work. The feature request was to spice up the credit card form like fab.com. It highlighted the correct logo when you enter the credit card numbers, auto-tabs(not my decision), and changing input fields if it was an AMEX card. I tried to find a plugin or a tutorial but there wasn't really much out there. So I went with http://webstandardssherpa.com/reviews/auto-detecting-credit-card-type
barebone code to create my own. Hope it helps someone.

The first thing I did was break the input field into 4 fields and added the four logos in the credit card partial by doing this :

.control-group
   = f.label :number, 'Number *', class: 'control-label'
   .controls
      = f.text_field :number, value:  '', required: true, autofocus: true
      = f.fields_for :number do |c|
        = c.text_field 'cnumber1', autofocus: true, value: '', maxlength: 4, size: 4, tabindex: 1 
        = c.text_field 'cnumber2', value: '', maxlength: 4, size: 4, tabindex: 2 
        = c.text_field 'cnumber3', value: '', maxlength: 4, size: 4, tabindex: 3
        = c.text_field 'cnumber4', value: '', maxlength: 4, size: 4, tabindex: 4
     #cc-logo
       #amex_logo
         =image_tag("amex.jpg")
      #discover_logo
         =image_tag("dsc.jpg")
      #mastercard_logo 
         =image_tag("mc.jpg")
      #visa_logo
        =image_tag("visa.jpg")

Next I added a javascript file and added this:

function getCreditCardType(accountNumber)
{
  var accountNumber =         document.getElementById('transaction_credit_card_number_cnumber1').value; 
  var result = "default";

  if(/^5[1-5]/.test(accountNumber))
  {
    result = "mastercard";
  }

  else if (/^4/.test(accountNumber))
  {
    result = "visa";
  }

  else if (/^3[47]/.test(accountNumber))
  {
    result = "amex";
  }

  else if (/^6/.test(accountNumber))
  {
    result = "discover";
  }

  else if (/^$/.test(accountNumber))
  {
    result = "default"
  }

    return result;
}

Basically what the above does is identifying what type of card it is. I used regex and the CC standards to test the number. I set the fields to a max of 4. The id 'transactioncreditcardnumbercnumber1' was auto generated by rails and can be found if you do an inspect element of the page in chrome.

Next up is the logic. It is kinda hacky but it got the job done!

function handleEvent(event)
{
  var value = event.target.value,
      type = getCreditCardType(value);

  switch (type)
  {
    case "mastercard":
      var logo = document.getElementById('mastercard_logo');
      {
        logo.style.opacity = "1.0";

        // IE fallback

        logo.style.filter = 'alpha(opacity=100)';

        break;
      }

    case "visa":
      var logo = document.getElementById('visa_logo');
      {
        logo.style.opacity = "1.0";

        // IE fallback

        logo.style.filter = 'alpha(opacity=100)';

        break;
      }

    case "amex":
      var logo = document.getElementById('amex_logo');
      var secondField = document.getElementById('transaction_credit_card_number_cnumber2')
      var thirdField = document.getElementById('transaction_credit_card_number_cnumber3')
      var fourthField = document.getElementById('transaction_credit_card_number_cnumber4')
      {
        logo.style.opacity = "1.0";

        // IE fallback

        logo.style.filter = 'alpha(opacity=100)';

        secondField.setAttribute("maxlength", "6");
        secondField.style.width = "90px";

        thirdField.setAttribute("maxlength", "5");
        thirdField.style.width = "60px";

        fourthField.setAttribute("type", "hidden");

        break;
      }

    case "discover":
      var logo = document.getElementById('discover_logo');
      {
        logo.style.opacity = "1.0";

        // IE fallback

        logo.style.filter = 'alpha(opacity=100)';

        break;
      }

    case "default":
      var master = document.getElementById('mastercard_logo');
      var visa = document.getElementById('visa_logo');
      var amex = document.getElementById('amex_logo');
      var discover = document.getElementById('discover_logo');
      var secondField = document.getElementById('transaction_credit_card_number_cnumber2')
      var thirdField = document.getElementById('transaction_credit_card_number_cnumber3')
      var fourthField = document.getElementById('transaction_credit_card_number_cnumber4')
      {

        master.style.opacity = "0.4";
        visa.style.opacity = "0.4";
        amex.style.opacity = "0.4";
        discover.style.opacity = "0.4";

        // IE fallback

        master.style.filter = 'alpha(opacity=40)';
        visa.style.filter = 'alpha(opacity=40)';
        amex.style.filter = 'alpha(opacity=40)';
        discover.style.filter = 'alpha(opacity=40)';

        secondField.setAttribute("maxlength", "4");
        secondField.style.width = "40px";

        thirdField.setAttribute("maxlength", "4");
        thirdField.style.width = "40px";

        fourthField.setAttribute("type", "text");

        break;
      }
  }
}

All this will probably need to be refactored but I think it breaks everything down pretty clearly. My opacity is set to 0.4 as a default and when each case is met the corresponding logo's opacity changes to 1.0. Also if you take a look at the AMEX case it also changes the input field. I hid the last input field and made the width of the second and third field 90px and 60px. It allows for 6 numbers and 5 numbers, respectively.

My last case is the default case which returns everything back to normal when all the numbers are erased. Notice that I only check the first 4 numbers of the credit card.

Now comes the end. auto tabbing and listening for "keyup" which activates the js when you type and "blur" which activates when you paste.

$(function(){
  $('.control-group .controls').keyup(function(e){
    if ($(this).val().length==$(this).attr('maxlength'))
    $(this).next(':input').focus()
    else 
    if ($(this).val().length==0)
    $(this).prev(':input').focus()

  })
})

  document.addEventListener("DOMContentLoaded", function(){
    var ccbox = document.getElementById("transaction_credit_card_number_cnumber1");
    ccbox.addEventListener("keyup", handleEvent, false);
    ccbox.addEventListener("blur", handleEvent, false);
  }, false);

OK so I lied! I used a line of jquery that allows for autotab forward and backwards.

And that's it! If you have any questions, better solution, or refactoring, please feel free to comment below. I am curious on how I can write that jquery function in regular javascript.

Thanks! I hope it helps someone!