I have an input field which has a data manipulation and is a decimal field. Everything works fine except when I put in more than 3 numbers it will lose the current caret and set it to the end of the field because of the field formatting. Example: 123 works fine 1234 will result in 1’234.00 and the caret is after the last 0. How is it possible to set the caret back to its original position? (Between 4 and the .)
function thousenderSign(number) {
number = '' + number;
if (number.length > 3) {
var mod = number.length % 3;
var output = (mod > 0 ? (number.substring(0, mod)) : '');
for (i = 0; i < Math.floor(number.length / 3); i++) {
if ((mod == 0) && (i == 0)) {
output += number.substring(mod + 3 * i, mod + 3 * i + 3);
} else {
output += "'" + number.substring(mod + 3 * i, mod + 3 * i + 3); // set the sign
}
}
return (output);
} else return number;
}
ko.extenders.numeric = function(target, precision) {
var result = ko.pureComputed({
read: target,
write: function(newValue) {
var current = target();
var roundingMultiplier = Math.pow(10, precision);
var newValueAsNum = null;
if (newValue !== undefined && newValue !== 0 && newValue !== null) {
newValueAsNum = newValue.toString().replace("'", "");
// provide only int fort he function
var onlyInt = newValueAsNum.split(".");
// Remove more then 2 digits after the dot
if (onlyInt.length > 1 && onlyInt[1].length > 2) {
onlyInt[1] = onlyInt[1].toString().substring(0, 2);
}
}
var valueToWrite = (Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier) === 0 ? null : Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
// thousender sign
if (newValueAsNum !== null && newValueAsNum.length > 3) {
valueToWrite = thousenderSign(onlyInt[0]) + "." + (onlyInt.length > 1 ? onlyInt[1] : '00');
}
if (valueToWrite !== current) {
target(valueToWrite);
} else {
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
}).extend({
notify: 'always'
});
result(target());
return result;
};
function ExampleViewModel() {
self = this;
self.counterofferPremium = ko.observable().extend({
numeric: 2
});
};
var viewModel = new ExampleViewModel();
ko.applyBindings(viewModel);
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
</head>
<body>
<input data-bind="value: counterofferPremium, valueUpdate: 'afterkeydown'" type="text" />
</body>
</html>
The simplest thing to do is get rid of the
valueUpdate
setting so that the formatting happens after the user is done editing the number.To have it work interactively, you need to add an
input
event handler thatsetTimeout
to allow the reformatting to happenAlso note that your formatter gets weird for very long numbers. You might want to replace it with a call to
toLocaleString
with some additional substitutions.