mrchad
mrchad

Reputation: 809

Insert dash after every 4th character in input

I want insert a dash after every 4th character in input. I have a credit card input box. When a user is typing and reaches each 4th character, then jQuery will insert a hyphen (-).

For example: 1234-5678-1234-1231

UPDATE: I'm trying some codes and i think i'm so close to correct code but i have some problems. Here is my code sample;

$('.creditCardText').keyup(function() {

var cardValue = $('.creditCardText').val(),
    cardLength = cardValue.length;

if ( cardLength < 5 ) {
    if ( cardLength % 4 == 0 ) {
        console.log('4 lük geldi');
        cardValue += "-";
        $('.creditCardText').val(cardValue);
    }
} else {
    if ( cardLength % 5 == 0 ) {
        console.log('5 lük geldi');
        cardValue += "-";
        $('.creditCardText').val(cardValue);

    }
}

});

Upvotes: 41

Views: 89697

Answers (8)

Hassan Qasim
Hassan Qasim

Reputation: 483

Most easiest way is the following using simple javascript onkey and function... it will put a dash hyphen after every 3 characters you input/type.

function addDash(element) {
  let ele = document.getElementById(element.id);
  ele = ele.value.split('-').join(''); // Remove dash (-) if mistakenly entered.

  let finalVal = ele.match(/.{1,3}/g).join('-');
  document.getElementById(element.id).value = finalVal;
}
<input type="text" class="form-control" name="sector" id="sector" onkeyup="addDash(this)" required>

Upvotes: 2

Brajinder Singh
Brajinder Singh

Reputation: 167

All others who have answered above me are right and their code is definitely short and neat, but is a bit advance, in the sense that they are either using regular expressions or a plugin. Something like this can also be achieved with basic js/jquery, which, judging from your sample code you are trying to achieve. As this question is around 3 years old, you must've gotten what you had wanted by now, but yes, you were close.. This is what you should have tried:

$('.creditCardText').keyup(function() {
  var cctlength = $(this).val().length; // get character length

  switch (cctlength) {
    case 4:
      var cctVal = $(this).val();
      var cctNewVal = cctVal + '-';
      $(this).val(cctNewVal);
      break;
    case 9:
      var cctVal = $(this).val();
      var cctNewVal = cctVal + '-';
      $(this).val(cctNewVal);
      break;
    case 14:
      var cctVal = $(this).val();
      var cctNewVal = cctVal + '-';
      $(this).val(cctNewVal);
      break;
    default:
      break;
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<input type="text" class="creditCardText" maxlength="19" />

JSFiddle Link

Upvotes: 1

Su Ming Yuan
Su Ming Yuan

Reputation: 125

By modifying the suggestion of @think123 and @TheStoryCoder, I added selectionStart and SelectionEnd for cursor. After that increase cursor position at suitable place and modify the cursor position. It should solve the cursor position is at not as expected position.

$('.creditCardText').keyup(function() {

  var ss, se, obj;
  obj = $(this);
  ss = obj[0].selectionStart;
  se = obj[0].selectionEnd;

  var curr = obj.val();

  var foo = $(this).val().split("-").join(""); // remove hyphens
  if (foo.length > 0) {
    foo = foo.match(new RegExp('.{1,4}', 'g')).join("-");
  }

  if (((curr.length % 5 == 0) && ss == se && ss == curr.length) || (ss == se && (ss % 5 == 0))) {
    ss += 1;
    se += 1;
  }

  if (curr != foo) {
    $(this).val(foo);
    obj[0].selectionStart = ss;
    obj[0].selectionEnd = se;
  }

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="creditCardText" type="text">

Upvotes: 3

pmrotule
pmrotule

Reputation: 9692

If you are looking for a pure Javascript solution, look at my function below. It supports the American Express format (15 digits) as well as Visa, MasterCard and others (16 digits).

Watch out for the simple solutions that will replace the whole value and always put the focus at the end of the input: it can be annoying if the user edits what he previously entered.

input_credit_card = function(input) {
  var format_and_pos = function(char, backspace) {
    var start = 0;
    var end = 0;
    var pos = 0;
    var separator = " ";
    var value = input.value;

    if (char !== false) {
      start = input.selectionStart;
      end = input.selectionEnd;

      if (backspace && start > 0) // handle backspace onkeydown
      {
        start--;

        if (value[start] == separator) {
          start--;
        }
      }
      // To be able to replace the selection if there is one
      value = value.substring(0, start) + char + value.substring(end);

      pos = start + char.length; // caret position
    }

    var d = 0; // digit count
    var dd = 0; // total
    var gi = 0; // group index
    var newV = "";
    var groups = /^\D*3[47]/.test(value) ? // check for American Express
      [4, 6, 5] : [4, 4, 4, 4];

    for (var i = 0; i < value.length; i++) {
      if (/\D/.test(value[i])) {
        if (start > i) {
          pos--;
        }
      } else {
        if (d === groups[gi]) {
          newV += separator;
          d = 0;
          gi++;

          if (start >= i) {
            pos++;
          }
        }
        newV += value[i];
        d++;
        dd++;
      }
      if (d === groups[gi] && groups.length === gi + 1) // max length
      {
        break;
      }
    }
    input.value = newV;

    if (char !== false) {
      input.setSelectionRange(pos, pos);
    }
  };

  input.addEventListener('keypress', function(e) {
    var code = e.charCode || e.keyCode || e.which;

    // Check for tab and arrow keys (needed in Firefox)
    if (code !== 9 && (code < 37 || code > 40) &&
      // and CTRL+C / CTRL+V
      !(e.ctrlKey && (code === 99 || code === 118))) {
      e.preventDefault();

      var char = String.fromCharCode(code);

      // if the character is non-digit
      // OR
      // if the value already contains 15/16 digits and there is no selection
      // -> return false (the character is not inserted)

      if (/\D/.test(char) || (this.selectionStart === this.selectionEnd &&
          this.value.replace(/\D/g, '').length >=
          (/^\D*3[47]/.test(this.value) ? 15 : 16))) // 15 digits if Amex
      {
        return false;
      }
      format_and_pos(char);
    }
  });

  // backspace doesn't fire the keypress event
  input.addEventListener('keydown', function(e) {
    if (e.keyCode === 8 || e.keyCode === 46) // backspace or delete
    {
      e.preventDefault();
      format_and_pos('', this.selectionStart === this.selectionEnd);
    }
  });

  input.addEventListener('paste', function() {
    // A timeout is needed to get the new value pasted
    setTimeout(function() {
      format_and_pos('');
    }, 50);
  });

  input.addEventListener('blur', function() {
    // reformat onblur just in case (optional)
    format_and_pos(this, false);
  });
};

input_credit_card(document.getElementById('credit-card'));
<form action="" method="post">
  <fieldset>
    <legend>Payment</legend>
    <div>
      <label for="credit-card">Credit card</label>
      <input id="credit-card" type="text" autocomplete="off" />
    </div>
  </fieldset>
</form>

View on jsFiddle

Upvotes: 7

rap-2-h
rap-2-h

Reputation: 32068

Based on @think123 answer, in vanilla JS, without JQuery:

document.querySelector('.creditCardText').addEventListener('input', function(e) {
  var foo = this.value.split("-").join("");
  if (foo.length > 0) {
    foo = foo.match(new RegExp('.{1,4}', 'g')).join("-");
  }
  this.value = foo;
});
<input class="creditCardText" type="text">

I know the question is about JQuery but I think this answer could help too.

Upvotes: 19

Zerium
Zerium

Reputation: 17333

I've fixed up your code, but still strongly suggest server validation and using four text boxes, and smartly switching between them:

$('.creditCardText').keyup(function() {
  var foo = $(this).val().split("-").join(""); // remove hyphens
  if (foo.length > 0) {
    foo = foo.match(new RegExp('.{1,4}', 'g')).join("-");
  }
  $(this).val(foo);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" class="creditCardText" />

View on jsFiddle

Upvotes: 21

tnkh
tnkh

Reputation: 1839

You can achieved with vanilla JS and do not require plugin to do that. Refer to the code below. You can change the var split to suit your needs. Credits to https://webdesign.tutsplus.com/tutorials/auto-formatting-input-value--cms-26745.

(function($, undefined) {

    "use strict";

    // When ready.
    $(function() {
        
        var $form = $( "#form" );
        var $input = $form.find( "input" );

        $input.on( "keyup", function( event ) {
            
            console.log('sss')
            // When user select text in the document, also abort.
            var selection = window.getSelection().toString();
            if ( selection !== '' ) {
                return;
            }
            
            // When the arrow keys are pressed, abort.
            if ( $.inArray( event.keyCode, [38,40,37,39] ) !== -1 ) {
                return;
            }
            
            var $this = $(this);
            var input = $this.val();
                    input = input.replace(/[\W\s\._\-]+/g, '');
                
                var split = 4;
                var chunk = [];
               
                for (var i = 0, len = input.length; i < len; i += split) {                              chunk.push( input.substr( i, split ) );
                }

                 console.log(chunk)
                $this.val(function() {
                    return chunk.join("-");
                });
        
        } );
        
        /**
         * ==================================
         * When Form Submitted
         * ==================================
         */
        $form.on( "submit", function( event ) {
            
            var $this = $( this );
            var arr = $this.serializeArray();
        
            for (var i = 0; i < arr.length; i++) {
                    arr[i].value = arr[i].value.replace(/[($)\s\._\-]+/g, ''); // Sanitize the values.
            };
            
            console.log( arr );
            
            event.preventDefault();
        });
        
    });
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="form" method="post" action="">

        <label for="number">Enter number</label>
        <div class="flex">
            <input id="number" name="number" type="text" maxlength="15" />
        </div>

</form>

Upvotes: 0

Nick
Nick

Reputation: 9154

I absolutely love this plugin for automatic formatting: here.

So long as you're already using JQuery, that is.

You could easily force the dashes in with a single line of code, like follows:

$("#credit").mask("9999-9999-9999-9999");

When the user types in the field, the dashes will automatically appear in the right spot, and they will not be able to delete them.

In addition, you can accommodate for different lengths or formats of credit cards with the ? character in your mask. For example, to accept inputs of 14 and 16 digits, you would do the following:

$("#credit").mask("9999-9999-9999-99?99");

Do keep in mind that this is only a client side validation


Edit: The mask plugin assumes that there is one, or finitely many, correct formats for the field. For example, there are only a few formats that credit card numbers come in. The plugin is there to ensure that your input will only be in one of those formats.

So technically, if you want a dash after every four digits, but for any number of digits, then this plugin is not right for you.

I would suggest you restrict the possible inputs to be reasonable, as there is certainly no such thing as a 1000-digit long credit card. But if you really want that functionality, you'll have to write the script yourself or find another plugin. As of this time I'm not aware of one.

Upvotes: 30

Related Questions