I have to format an account number input field like below:
Desired format: 123456 1234 12 1
But, the regex which I wrote formats the text field as below:
Current format: 1234 1234 1234 1
Can someone please help me with the correct regex or logic to implement this?
function cc_format(value) {
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '')
var matches = v.match(/\d{4,13}/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('account-number').oninput = function() {
this.value = cc_format(this.value)
}
}
<form>
<div>AccountNumber</div><br/>
<input id="account-number" value="" placeholder="123456 1234 12 1">
</form>
You can get groups of 6, instead of groups of 4, then, as soon as your second group gets over 4 characters long, you can insert a space at the desired position. Here's a proof of concept:
function cc_format(value) {
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '')
var matches = v.match(/\d{6,13}/g);
var match = matches && matches[0] || ''
var parts = []
for (i = 0, len = match.length; i < len; i += 6) {
parts.push(match.substring(i, i + 6))
}
if (parts.length > 1 && parts[1].length > 4) {
parts[1] = [parts[1].slice(0, 4), ' ', parts[1].slice(4)].join('');
}
if (parts.length) {
return parts.join(' ')
} else {
return v
}
}
onload = function() {
document.getElementById('account-number').oninput = function() {
this.value = cc_format(this.value)
}
}
<form>
<div>AccountNumber</div><br/>
<input id="account-number" value="" placeholder="123456 1234 12 1">
</form>
A slightly more elegant solution would be to use .slice() and .join() for the whole thing, which cleans up the code nicely. Here's an example:
function cc_format(value) {
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '');
if (v.length > 6)
v = [v.slice(0, 6), ' ', v.slice(6)].join('');
if (v.length > 11)
v = [v.slice(0, 11), ' ', v.slice(11)].join('');
if (v.length > 14)
v = [v.slice(0, 14), ' ', v.slice(14)].join('');
if (v.length > 16)
v = v.slice(0, 16);
return v;
}
onload = function() {
document.getElementById('account-number').oninput = function() {
this.value = cc_format(this.value)
}
}
<form>
<div>AccountNumber</div><br/>
<input id="account-number" value="" placeholder="123456 1234 12 1">
</form>
You can use following code, to format the code properly when user is typing. It works dynamically.
const normalize = elem => {
let value = elem.target.value;
const onlyNums = value.replace(/[^\d]/g, '');
if (onlyNums.length <= 6) {
return onlyNums;
} else if (onlyNums.length <= 10) {
return `${onlyNums.slice(0, 6)} ${onlyNums.slice(6)}`;
} else if (onlyNums.length <= 12) {
return `${onlyNums.slice(0, 6)} ${onlyNums.slice(6, 10)} ${onlyNums.slice(10, 12)}`;
}
return `${onlyNums.slice(0, 6)} ${onlyNums.slice(6, 10)} ${onlyNums.slice(10, 12)}
${onlyNums.slice(12, 13)}`;
};
const input = document.getElementById('input');
input.addEventListener('input', (e) => e.target.value = normalize(e));
<input type='text' id='input' value=''>
Related
I researched this on stack overflow, tried different answers but nothing worked for me. Can someone fix the problem please.
function spacingFunction() {
let varNumber = document.getElementById('cardnumber');
position = varNumber.selectionEnd;
varNumber.value = varNumber.value.replace(/[^\dA-Z]/g, '').replace(/(.{4})/g, '$1 ').trim()
varNumber.selectionEnd = position += ((varNumber.value.charAt(position - 1) === ' ' && varNumber.value.charAt(length - 1) === ' ' && length !== varNumber.value.length) ? 1 : 0);
}
<input id="cardnumber" placeholder="e.g. 1234 5678 9123 0000" maxlength="19" type="text" onkeydown="spacingFunction()">
I tried all fix examples from the site. Need solution
Your question was very unclear, but I believe that you asked to fix the spacing issue, here's a very good example on jsfiddle
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('cardnumber'));
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="cardnumber" placeholder="e.g. 1234 5678 9123 0000" maxlength="19" type="text" onkeydown="spacingFunction()">
<script src="script.js"></script>
</body>
</html>
As the title says I am using a math-expression library to do my calculations but I am having trouble figuring out the logic for decimals and how to prevent two decimals in one number inside an array. I have highlighted the part that is giving me trouble.
Here is my code sandbox link https://codesandbox.io/s/youthful-frost-2s6v6?file=/src/HookClaculator.js:181-2221
const [input, setInput] = useState([0]);
const [notANum, setNotANum] = useState("");
const [AC, setAC] = useState("");
const handleInputOneClick = (e) => {
let checkInput = input;
checkInput = [...checkInput, parseInt(e, 10)];
console.log(checkInput);
if (checkInput[1] !== 0) {
setInput([...input, parseInt(e, 10)]);
if (input.length > 23) {
console.log("exceeded 23");
setInput(["MAX DIGIT LIMIT REACHED"]);
setTimeout(() => {
setInput([0]);
}, 500);
}
}
};
const handleSymbolClick = (e) => {
if (Number.isInteger(input[input.length - 1])) {
setInput([...input, e]);
} else if (input[input.length - 1] === ".") {
setInput([...input, e]);
} else if (typeof input[input.length - 1] === "string") {
input.pop();
setInput([...input, e]);
}
};
const handleDecimalClick = (e) => {
if (input[input.length - 1] === ".") {
setInput([...input]);
} else if (isNaN(input[input.length - 1])) {
setInput([...input, e]);
} **else if (Number.isInteger(input[input.length - 1])) {
setInput([...input, e]);
}**
};
const handleEqualsClick = (e) => {
let exp = "";
if (input[0] === 0 && input.length <= 1) {
console.log("hell yeah");
setNotANum(["NaN"]);
} else if (input.length > 1) {
console.log("input length is " + input.length);
input.forEach((el) => {
return (exp += el);
});
let value = mexp.eval(exp);
setInput([value]);
}
};
const handleClickReset = (e) => {
setAC(e);
setInput([0]);
};
return (
<div id="calculator-div">
<HookDisplay input={input} notANum={notANum} AC={AC} />
<HookButtons
inputOneClick={handleInputOneClick}
symbolClick={handleSymbolClick}
decimalClick={handleDecimalClick}
handleEqualsButtonClick={handleEqualsClick}
handleClickReset={handleClickReset}
/>
</div>
);
};
return (
<div id="calculator-div">
<HookDisplay input={input} notANum={notANum} AC={AC} />
<HookButtons
inputOneClick={handleInputOneClick}
symbolClick={handleSymbolClick}
decimalClick={handleDecimalClick}
handleEqualsButtonClick={handleEqualsClick}
handleClickReset={handleClickReset}
/>
</div>
);
};
I think before pushing the decimal to the array you can ensure if it'll create a valid expression.
As currently the calculator supports basic operations, a number can never have more than one decimal and operands can only be one more than than the operators, leveraging the stated fact. This condition will work (inside handleDecimalClick):
let lastIndex = -1;
for (let i = input.length - 1; i >= 0; i--) {
if (input[i] === ".") {
lastIndex = i;
} else if (
input[i] === "+" ||
input[i] === "-" ||
input[i] === "*" ||
input[i] === "/"
) {
break;
}
}
if (lastIndex !== -1) return;
Also, for extra protection, added a regex to check if the expression is valid before it goes for evaluation (added the below lines in handleEquals):
const inp = input.join("");
const regex = /(?:(?:^|[-+_*/])(?:\s*-?\d+(\.\d+)?(?:[eE][+-]?\d+)?\s*))+$/;
if (!regex.test(inp)) {
return;
}
I forked your codesandbox and added the fix.
I want to enter a "/" when user enters MM(2 digit) so it will be like MM/YYYY.
I have done similar for credit card number input which insert a space after 4 digit on keypress.
let ccNumber = e.target.value.split(" ").join("");
if (ccNumber.length > 0) {
ccNumber = ccNumber.match(new RegExp('.{1,4}', 'g')).join(" ");
}
e.target.value = ccNumber;
Fiddle
This works with
Regular keyboard input
Copy/Cut/Paste
Selected text
Adding the /
Because you're programmatically adding the / character, you have to update the cursor position whenever that affects the new input value. This can be more than one character if the user is pasting something. Most of the code complexity revolves around this issue.
There are a lot of comments in the code explaining the various situations that come up because of the /.
Full Code
var date = document.getElementById('date');
date.addEventListener('keypress', updateInput);
date.addEventListener('change', updateInput);
date.addEventListener('paste', updateInput);
date.addEventListener('keydown', removeText);
date.addEventListener('cut', removeText);
function updateInput(event) {
event.preventDefault();
var string = getString(event);
var selectionStart = this.selectionStart;
var selectionEnd = this.selectionEnd;
var selectionLength = selectionEnd - selectionStart;
var sanitizedString = string.replace(/[^0-9]+/g, '');
// Do nothing if nothing is added after sanitization
if (sanitizedString.length === 0) {
return;
}
// Only paste numbers that will fit
var valLength = date.value.replace(/[^0-9]+/g, '').length;
var availableSpace = 6 - valLength + selectionLength;
// If `/` is selected it should not count as available space
if (selectionStart <= 2 && selectionEnd >= 3) {
availableSpace -= 1;
}
// Remove numbers that don't fit
if (sanitizedString.length > availableSpace) {
sanitizedString = sanitizedString.substring(0, availableSpace);
}
var newCursorPosition = selectionEnd + sanitizedString.length - selectionLength;
// Add one to cursor position if a `/` gets inserted
if (selectionStart <= 2 && newCursorPosition >= 2) {
newCursorPosition += 1;
}
// Previous input value before current cursor position
var valueStart = date.value.substring(0, this.selectionStart);
// Previous input value after current cursor position
var valueEnd = date.value.substring(this.selectionEnd, date.value.length);
var proposedValue = valueStart + sanitizedString + valueEnd;
// Remove anything that's not a number
var sanitized = proposedValue.replace(/[^0-9]+/g, '');
format(sanitized);
this.setSelectionRange(newCursorPosition, newCursorPosition);
}
function removeText(event) {
if (event.key === 'Backspace' || event.type === 'cut') {
event.preventDefault();
var selectionStart = this.selectionStart;
var selectionEnd = this.selectionEnd;
var selectionLength = selectionEnd - selectionStart;
// If pressing backspace with no selected text
if (selectionLength === 0 && event.type !== 'cut') {
selectionStart -= 1;
// Remove number from before `/` if attempting to delete `/`
if (selectionStart === 2) {
selectionStart -= 1;
}
}
var valueStart = date.value.substring(0, selectionStart);
var valueEnd = date.value.substring(selectionEnd, date.value.length);
// Account for added `/`
if (selectionStart === 2) {
selectionStart += 1;
}
var proposedValue = valueStart + valueEnd;
var sanitized = proposedValue.replace(/[^0-9]+/g, '');
format(sanitized);
this.setSelectionRange(selectionStart, selectionStart);
}
}
function getString(event) {
if (event.type === 'paste') {
var clipboardData = event.clipboardData || window.clipboardData;
return clipboardData.getData('Text');
} else {
return String.fromCharCode(event.which);
}
}
function format(sanitized) {
var newValue;
var month = sanitized.substring(0, 2);
if (sanitized.length < 2) {
newValue = month;
} else {
var year = sanitized.substring(2, 6);
newValue = month + '/' + year;
}
date.value = newValue;
}
<input id="date" type="text" maxlength="7">
Try:
var date = document.getElementById('date');
date.addEventListener('keypress', function (event) {
var char = String.fromCharCode(event.which),
offset = date.selectionStart;
console.log(offset)
if (/\d/.test(char) && offset < 7) {
if (offset === 2) {
offset += 1;
}
date.value = date.value.substr(0, offset) + char + date.value.substr(offset + 1);
date.selectionStart = date.selectionEnd = offset + 1;
}
if (!event.keyCode) {
event.preventDefault();
}
});
<input id="date" type="text" value="mm/yyyy" maxlength="6" size="6">
function keypress(elem) { // get Input
if (typeof elem == 'string') {
if (document.getElementById(elem)) elem = document.getElementById(elem);
if (typeof elem == 'string') elem = document.getElementsByName(elem).item(0);
}
const el = elem; //handle error if not found input
el.maxLength = 19;
el.addEventListener('keypress', function (e) {
const t = e.keyCode || e.which
if (t == 8 || (t > 47 && t < 58)) { // limit numeric characters and backspace
if (t != 8) {
if (el.value.length == 2) el.value += '/';
if (el.value.length == 5) el.value += '/';
if (el.value.length == 10) el.value += ' ';
if (el.value.length == 13) el.value += ':';
if (el.value.length == 16) el.value += ':';
}
} else {
e.preventDefault();
}
});}
In c# you can do this
String.format(5000, "$###,###,##0.00;-$###,###,##0.00;$0.00")
Which will output: $5,000
Or you can do this
String.format(-5000, "$###,###,##0.00;-$###,###,##0.00;$0.00")
Which will output: -$5,000
How do I do the same in Javascript??
UPDATE: I would also need to format a currency like this
String.format(-5000, "###.###.##0.00€;-###,###,##0.00€;0.00€")
Which would output: 5.000,00 €
you should really consider using toLocaleString so your code can rely on configuration settings like locale and currency rather than customized string format patterns.
const formatCurrency = (num, locale = 'en-US', currency = 'USD', minimumFractionDigits = 2) => {
if (isNaN(num)) {
return num;
}
return num.toLocaleString(locale, {style: 'currency', currency, minimumFractionDigits});
};
Here is an example fiddle
I Ended up rolling my own:
app.filter('formatMoney', ['$filter', function ($filter) {
return function (value, format) {
var v = format.split(';');
var index = 2;
if (value > 0)
index = 0;
else if (value < 0)
index = 1;
else {
return v[index];
}
var len = v[index].length;
var fIndex = v[index].indexOf('#');
var lIndex = v[index].lastIndexOf('0');
var f = v[index].substring(fIndex, lIndex + 1);
var symbolFirst = '';
var symbolLast = '';
if (lIndex !== len - 1) {
symbolLast = v[index].substring(len, len - 1);
}
if (fIndex > 0) {
symbolFirst = v[index].substring(0, fIndex);
}
var valueStr = value.toFixed(2).toString();
for (var i = f.length - 1; i > 0 && valueStr.length > 0; i--) {
var slice = valueStr.slice(-1);
if (f[i] === '#' || f[i].isNumeric()) {
valueStr = valueStr.slice(0, -1);
if (slice.isNumeric()) {
f = f.replaceAt(i, slice);
var j = valueStr.length - 1;
while (j > 0 && !valueStr[j].isNumeric()) {
valueStr = valueStr.slice(0, -1);
j = j - 1;
}
}
}
}
return symbolFirst + f.substr(f.search(/\d/), f.length - 1) + symbolLast;
};
}]);
I tried to research the answer to this question but I'm lost. I am trying to make a one search bar that automatically puts a dash in the phone number. I've solved that.
The next part is the challenging part. How can I make it always do XXX-XXX-XXXX, even if the characters pasted were something like 555 555 1212 or 555---555-1212, where it will only reel back the number and output with 555-555-1212. It shouldn't count the spaces or extra dashes as a character.
I found: http://www.jotform.com/answers/15202-can-I-add-script-to-my-form-that-will-automatically-add-hyphens-in-between-the-3-digit-area-code-and-also-the-3-digit-prefix
I changed it just a bit by adding:
<SCRIPT LANGUAGE="JavaScript">
function addDashes(f)
{
f.value = f.value.slice(0,3)+"-"+f.value.slice(3,6)+"-"+f.value.slice(6,15);
}
</SCRIPT>
<input id="input_4" class="form-textbox" maxlength="15" name="atn" size="25" onBlur='addDashes(this)' />
Right now, this works only if the user puts 5555555555 and automatically turns it into 555-555-5555. I'm trying to figure out how to take something like 5-55555-5555 and turn it into 555-555-5555. Currently, it makes it 5-5-555-5-5555.
See my dilemma? lol. It can't be php or any server side scripting as this must be able to run on a desktop.
Resolution:
<SCRIPT LANGUAGE="JavaScript">
function addDashes(f)
{
f.value = f.value.replace(/\D/g, '');
f.value = f.value.slice(0,3)+"-"+f.value.slice(3,6)+"-"+f.value.slice(6,15);
}
</SCRIPT>
First, clean your input by deleting all chars that are not numbers (ref.: Regex to replace everything except numbers and a decimal point)
Then, you put your dashes.
function addDashes(f)
{
f_val = f.value.replace(/\D[^\.]/g, "");
f.value = f_val.slice(0,3)+"-"+f_val.slice(3,6)+"-"+f_val.slice(6);
}
I have a strong tendency to treat phone numbers as a straight string of 10 digits with no formatting (so I can apply formatting to them on-the-fly, as needed and so searching and comparison is simpler), although that may change if I ever have to deal with international phone numbers. If all you're dealing with is US phone numbers, this will work nicely (formats it as it's typed):
function addDashes(f) {
var r = /(\D+)/g,
npa = '',
nxx = '',
last4 = '';
f.value = f.value.replace(r, '');
npa = f.value.substr(0, 3);
nxx = f.value.substr(3, 3);
last4 = f.value.substr(6, 4);
f.value = npa + '-' + nxx + '-' + last4;
}
Here's a fiddle: http://jsfiddle.net/EYuk5/
transform with string method replace
let phone = '0884332212'.replace(/^(\d{3})(\d{3})(\d{4})/, '$1-$2-$3')
console.log(phone)
// => 088-433-2212
I did this
function addDashesToNumber(number){
const numWithoutDashes = number.replace(/[^0-9]/g, '')
if(numWithoutDashes.length > 10) return number.slice(0, -1)
const dashPlaces = [3, 6]
return numWithoutDashes
.split('')
.reduce((acc, curr, i) => dashPlaces.includes(i) ? [...acc, '-', curr] : [...acc, curr], [])
.join('')
}
Try this:
function dashedNumber(value){
const afterIndices = [3,6,8];
const length = value.length;
let newValue = ''
for(let i=0; i<length; i++){
if(afterIndices.includes(i))
newValue+='-'
newValue+=value[i];
}
return newValue;
}
Here's a fiddle: https://jsfiddle.net/v9gq5jkw/.
<input id="phone">
function phone_formatting(ele, restore) {
var new_number,
selection_start = ele.selectionStart,
selection_end = ele.selectionEnd,
number = ele.value.replace(/\D/g, '');
if (number.length > 2) {
new_number = number.substring(0, 3) + '-';
if (number.length === 4 || number.length === 5) {
new_number += number.substr(3);
} else if (number.length > 5) {
new_number += number.substring(3, 6) + '-';
}
if (number.length > 6) {
new_number += number.substring(6);
}
} else {
new_number = number;
}
ele.value = (new_number.length > 12) ? new_number.substring(0, 12) : new_number;
if (new_number.slice(-1) === '-' && restore === false &&
(new_number.length === 8 && selection_end === 7) ||
(new_number.length === 4 && selection_end === 3)) {
selection_start = new_number.length;
selection_end = new_number.length;
} else if (restore === 'revert') {
selection_start--;
selection_end--;
}
ele.setSelectionRange(selection_start, selection_end);
}
function phone_number_check(field, e) {
var key_code = e.keyCode,
key_string = String.fromCharCode(key_code),
press_delete = false,
dash_key = 189,
delete_key = [8, 46],
direction_key = [33, 34, 35, 36, 37, 38, 39, 40],
selection_end = field.selectionEnd;
if (delete_key.indexOf(key_code) > -1) {
press_delete = true;
}
if (key_string.match(/^\d+$/) || press_delete) {
phone_formatting(field, press_delete);
} else if (direction_key.indexOf(key_code) > -1) {} else if (dash_key === key_code) {
if (selection_end === field.value.length) {
field.value = field.value.slice(0, -1)
} else {
field.value = field.value.substring(0, (selection_end - 1)) + field.value.substr(selection_end)
field.selectionEnd = selection_end - 1;
}
} else {
e.preventDefault();
phone_formatting(field, 'revert');
}
}
document.getElementById('phone').onkeyup = function(e) {
phone_number_check(this, e);
}
Beside adding dashes, you will need to deal with the position of the cursor, especially in case of deletion.
This AMD module does exactly that: https://github.com/whenyoubelieve2014/us-telephone-input