I am working on a ReactJS application and have an input which can have figures in the millions. I am using the following function to format the number with commas:
return Number(number).toLocaleString('en-GB', { minimumFractionDigits: 2 });
On the onChange prop for the input I have the following to stop the cursor jumping to the end:
const caret = e.target.selectionStart;
const element = e.target;
window.requestAnimationFrame(() => {
element.selectionStart = caret;
element.selectionEnd = caret;
});
When trying to change the second figure in one million number '1,000,000'
, deleting the second zero results in the cursor appearing after the second figure instead of the first figure. How can I make sure the cursor appears in the expected position when deleting digits in a seven-figure number?
Appreciate any advice
const [value, setValue] = useState("1000000");
const displayValue = Number(value).toLocaleString("en-GB", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const handleChange = e => {
const oldLen = displayValue.length;
const element = e.target;
let rawString = element.value;
let caret = element.selectionStart;
// block removing decimal point
if (caret === element.value.length - 2 && element.value.length < oldLen) {
rawString = rawString.slice(0, caret) + "." + rawString.slice(caret);
}
// block removing commas
if (displayValue.charAt(caret) === "," && rawString.charAt(caret) !== ",") {
rawString = rawString.slice(0, caret) + "," + rawString.slice(caret);
}
const firstCommaAt = rawString.search(/,/g);
const newLen = rawString.length;
// caret position correction
if (newLen > oldLen) {
if (
(firstCommaAt === 3 && caret > firstCommaAt) ||
firstCommaAt === 4 ||
newLen === 7
) {
caret += 1;
}
}
if (newLen < oldLen) {
if (firstCommaAt === 1 && caret > firstCommaAt) {
caret -= 1;
}
}
// store parseable value
setValue(rawString.replace(/,/g, ""));
window.requestAnimationFrame(() => {
element.selectionStart = caret;
element.selectionEnd = caret;
});
};
return (
<input value={displayValue} onChange={e => handleChange(e)} />
)
working example: https://codesandbox.io/s/input-with-usestate-z48s2