40

I'm really new in JavaScript and I would like to add to my input text, space insertion for IBAN account registering.

<input type="text" name="iban" onkeyup="if(this.value.length > 34){this.value=this.value.substr(0, 34);}" />

There is my input field; could someone tell me how I can do this?

Josh Crozier
  • 202,159
  • 50
  • 343
  • 273
Jackyto
  • 1,478
  • 3
  • 15
  • 32

11 Answers11

83

The existing answers are relatively long, and they look like over-kill. Plus they don't work completely (for instance, one issue is that you can't edit previous characters).

For those interested, according to Wikipedia:

Permitted IBAN characters are the digits 0 to 9 and the 26 upper-case Latin alphabetic characters A to Z.

Here is a relatively short version that is similar to the existing answers:

document.getElementById('iban').addEventListener('input', function (e) {
  e.target.value = e.target.value.replace(/[^\dA-Z]/g, '').replace(/(.{4})/g, '$1 ').trim();
});
<label for="iban">iban</label>
<input id="iban" type="text" name="iban" />

As stated above, the caveat is that you can't go back and edit previous characters. If you want to fix this, you would need to retrieve the caret's current position by initially accessing the selectionEnd property and then setting the caret's position after the regex formatting has been applied.

document.getElementById('iban').addEventListener('input', function (e) {
  var target = e.target, position = target.selectionEnd, length = target.value.length;
  
  target.value = target.value.replace(/[^\dA-Z]/g, '').replace(/(.{4})/g, '$1 ').trim();
  target.selectionEnd = position += ((target.value.charAt(position - 1) === ' ' && target.value.charAt(length - 1) === ' ' && length !== target.value.length) ? 1 : 0);
});
<label for="iban">iban</label>
<input id="iban" type="text" name="iban" />

You will notice that there is a slight issue when the character after the caret is a space (because the space wasn't accounted for when initially retrieving the caret's position to begin with). To fix this, the position is manually incremented if the succeeding character is a space (assuming a space was actually added - which is determined by comparing the length before and after replacing the characters).

Josh Crozier
  • 202,159
  • 50
  • 343
  • 273
  • What is a use case where `target.value.charAt(length - 1) === ' ' && length !== target.value.length` is useful? It sounds I can handle every edge case with just: `target.value.charAt(position - 1) === ' ' ? 1 : 0` – Mik378 Feb 14 '17 at 07:38
  • 1
    @Mik378 - Yeah, it's useful, it covers an additional edge case when the backspace key is used. If you have a value such as `1234 5678 9`, and you hit backspace and remove the `5`, you would expect the caret to be moved to the space before the `6` character as demonstrated in [this working example](https://jsfiddle.net/aujm8cu7/)... if we removed those edge case checks that you are referring to, and you remove the `5`, then the caret is moved after the `6` character as demonstrated in [this (not working) example](https://jsfiddle.net/aujm8cu7/1/) – Josh Crozier Feb 20 '17 at 05:04
  • 2
    Works for me :) a little improvement: if users type the country code in lowercase, no input happens. A `.toUpperCase()` after `e.target.value` fixes that. – Lea Rosema Jul 01 '17 at 16:07
  • Hi, how to do the same for ionic 3, I'm using angular 5 now. – Rajkumar K Jan 30 '18 at 12:52
  • 1
    This is the only solution I have found that works on Samsung Galaxy also – ESR May 10 '18 at 04:45
  • Two issues with it; if the caret is not at the end but e.g. at the before last position and the user starts typing, sometimes the caret doesn't stay at the before last position. Another issue is with Android 7+ devices. they update the caret position slightly later, that means it needs a `setTimeout()` before reading the caret location. – Rob Juurlink Oct 17 '18 at 15:01
  • Thank you really much for sharing this, i came across a "problem" when implementing this, it seems that if i paste the IBAN the focus won't be in the last char but 3 chars before that, any workaround for this? @JoshCrozier – Ricardo Costa Nov 18 '19 at 10:30
  • Try typing "17". Then move your carrot between "1" and "7". Now type "23456". This should result in "1234 567", but the carrot doesn't always stay in the correct position, so you get "1234 **65**7" instead. I tweaked [this answer](https://stackoverflow.com/a/39804917/11653883) to suit me instead. – Aaron Plocharczyk Jul 15 '20 at 16:17
  • `\w` (Any word character) rather than `\dA-Z` would be nice. – kissu Apr 27 '21 at 14:14
14

Using plain-JavaScript, I'd suggest:

function space(el, after) {
    // defaults to a space after 4 characters:
    after = after || 4;

    /* removes all characters in the value that aren't a number,
       or in the range from A to Z (uppercase): */
    var v = el.value.replace(/[^\dA-Z]/g, ''),
    /* creating the regular expression, to allow for the 'after' variable
       to be used/changed: */
        reg = new RegExp(".{" + after + "}","g")
    el.value = v.replace(reg, function (a, b, c) {
        return a + ' ';
    });
}

var el = document.getElementById('iban');
el.addEventListener('keyup', function () {
    space(this, 4);
});

JS Fiddle demo.

Somewhat belatedly, my rewrite of the above to handle strings, rather than DOM nodes:

function space(str, after) {
    if (!str) {
        return false;
    }
    after = after || 4;
    var v = str.replace(/[^\dA-Z]/g, ''),
        reg = new RegExp(".{" + after + "}", "g");
    return v.replace(reg, function (a) {
        return a + ' ';
    });
}

var el = document.getElementById('iban');
el.addEventListener('keyup', function () {
    this.value = space(this.value, 4);
});

JS Fiddle demo.

References:

David says reinstate Monica
  • 230,743
  • 47
  • 350
  • 385
2

You have to capture each group of 4 digits and then put a space between each group.

  $('input').blur(function () {
  //Replace each group 4 digits  with a group plus a space
        var reformat = this.value.replace(/(\d{4})/g, function(match){
        return match + " ";
        });
        this.value = reformat;
    })

And this one updates the element while typing

 //Keys pressed 0 times
var downed = 0; 
$('#test').keydown(function (g) {
    if(g.code.match("^Digit")){
        downed++;
      console.log(g)
    }

    if(downed == 1){
        var reformat = this.value.replace(/(\d{4}\s*)/g, function(match){
            //Strip spaces
            if(match.match(/\s/)){return match;}
            return match + " ";
    });
    console.log(reformat);
    this.value = reformat; 
    //Start recount
        downed = 0;
    }
});

Check out the fiddle

raam86
  • 6,283
  • 1
  • 25
  • 45
  • 1
    I really like the version that updates while typing. The only problem is that it doesn't put in the first space until you reach digit 6, and also behaves erratically if you back-space to correct an error. The end result is still good, but it might confuse a user. – TrapezeArtist Aug 11 '14 at 16:07
  • @TrapezeArtist nice suggestion, check out this fiddle https://jsfiddle.net/dr3vgezL/3/ – raam86 Mar 25 '19 at 20:51
2

The code from Josh Crozie is really nice, but not complete.

Two issues with it;

  • If the caret is not at the end but e.g. at the before last position and the user starts typing, sometimes the caret doesn't stay at the before last position
  • Another issue is with Android 7+ devices. Those devices update the caret position slightly later, that means it needs a setTimeout() before reading the caret location

The code below is based on the code of Josh Crozie, now with the two issues mentioned above fixed and a little more verbose for readability purpose:

var isAndroid = navigator.userAgent.indexOf("ndroid") > -1;
var element = document.getElementById('iban');

element.addEventListener('input', function () {
    if (isAndroid) {
        // For android 7+ the update of the cursor location is a little bit behind, hence the little delay.
        setTimeout(reformatInputField);
        return;
    }
    reformatInputField();
});

function reformatInputField() {
    function format(value) {
        return value.replace(/[^\dA-Z]/gi, '')
            .toUpperCase()
            .replace(/(.{4})/g, '$1 ')
            .trim();
    }
    function countSpaces(text) {
        var spaces = text.match(/(\s+)/g);
        return spaces ? spaces.length : 0;
    }

    var position = element.selectionEnd;
    var previousValue = element.value;
    element.value = format(element.value);

    if (position !== element.value.length) {
        var beforeCaret = previousValue.substr(0, position);
        var countPrevious = countSpaces(beforeCaret);
        var countCurrent = countSpaces(format(beforeCaret));
        element.selectionEnd = position + (countCurrent - countPrevious);
    }
}
<label for="iban">iban</label>
<input id="iban" type="text" name="iban" size="35" />
Rob Juurlink
  • 3,811
  • 3
  • 16
  • 18
2

I wrote a simple function extending David's function to handle the last space. Also you can specify the separator.

function spacify(str, after, c) {
    if (!str) {
        return false;
    }
    after = after || 4;
    c = c || " ";
    var v = str.replace(/[^\dA-Z]/g, ''),
        reg = new RegExp(".{" + after + "}", "g");
    return v.replace(reg, function (a) {
        return a + c;
    }).replace(/[^0-9]+$/, "");
}
console.log(spacify("123123123131",4," "))
console.log(spacify("12312312313",4,"-"))
Raj Sharma
  • 3,196
  • 3
  • 27
  • 38
1

for thousands on angular 4 in a pipe

integer = integer.replace(/[^\dA-Z]/g, '').replace(/(.{3})/g, '$1.').trim();
Suraj Rao
  • 28,186
  • 10
  • 88
  • 94
0

I need the same but for BVR/BVR+ swiss payment form. So what I need is add a space every 5 chars but from the end of the string.

Example : "52 86571 22001 00000 10520 15992" or sometimes shorter like "843 14293 10520 15992".

So, here is the solution by reversing the string before and after adding spaces if rev=1.

function space(str, stp, rev) {
    if (!str) {
        return false;
    }
    if (rev == 1) {
        str = str.split('').reverse().join('');
    }
    if(stp > 0) {
        var v = str.replace(/[^\dA-Z]/g, ''),
            reg = new RegExp(".{" + stp + "}", "g");
        str = v.replace(reg, function (a) {
            return a + ' ';
        });
    }
    if (rev == 1) {
        str = str.split('').reverse().join('');
    }
    return str;
}

Use :

var refTxt = space(refNum, 5, 1);

EDIT : PHP version added

function space($str=false, $stp=0, $rev= false) {

    if(!$str)
        return false;
    
    if($rev)
        return trim(strrev(chunk_split(strrev($str), $stp, ' ')));
    else
        return trim(chunk_split($str, $stp, ' '));
}
Meloman
  • 2,745
  • 3
  • 35
  • 39
0

This is the shortest version using JQuery on input with type number or tel:

$('input[type=number], input[type=tel]').on('input', function (e) {
     e.target.value = e.target.value.replace(/[^\dA-Z]/g, '').replace(/(.{4})/g, '$1 ').trim();
});

You can also change the 4 to any other character limit you want.

AlexioVay
  • 3,158
  • 2
  • 21
  • 41
0
onChangeText={number => {
 const data =
  number.length % 5 !== 4
    ? number
        .replace(/[^\dA-Z]/g, '')
        .replace(/(.{4})/g, '$1-')
        .trim()
    : number;
 this.setState({
  ...this.state,
  card: {...this.state.card, number: data},
 });
}}

If you are trying to use for text input to adjust with credit card then this method will help you solve the backspace problem too

Rahul Shakya
  • 737
  • 5
  • 12
-1

document.getElementById('iban').addEventListener('input', function (e) {
  e.target.value = e.target.value.replace(/[^\dA-Z]/g, '').replace(/(.{4})/g, '$1 ').trim();
});
<label for="iban">iban</label>
<input id="iban" type="text" name="iban" />
-1

To Add space after 4 Digits Useful to validate IBAN Number


document.getElementById('IBAN').addEventListener('input', function (e) {
  e.target.value = e.target.value.replace(/[^\dA-Z]/g, '').replace(/(.{4})/g, '$1 ').trim();
});

<label for="IBAN">IBAN</label>
<input id="IBAN" maxlength="14" type="text" name="IBAN" />

Apoorva Chikara
  • 2,534
  • 3
  • 11
  • 20