I'm new to knockout, and still learning how best to work with it. I have a few input fields in an app which are tied to a bunch of calculations that update in real time. The fields on their own work great, and all is fine...
EXCEPT, I need to format the input as the user enters it, for display only (the raw data must be retained for the calculations, but 3 should appear as 3% or in another field 3000000 should appear as 3,000,000 etc.). I have this somewhat working, but I think there's a major flaw with my solution as the result is consistently buggy and it's possible to break the input field entirely.
So, an example of one of the input fields, which ties to another field to always equal 100%:
<input id='sm' data-bind='textInput: s_smixe' readonly='true'>
Is bound to:
self.s_smixebase = ko.observable(30);
self.s_smixe = ko.pureComputed({
read: function(){
return this.s_smixebase();
},
write: function(value){
if (parseFloat(value)<100) {
var otherValue = 100 - parseFloat(value);
this.s_smixebase(value);
this.s_rmixebase(otherValue);
} else {
value = 100;
this.s_smixebase(value);
this.s_rmixebase(0);
}
},
owner: this
}).extend({percent:{}});
self.s_smixeraw = self.s_smixe.raw;
Which is then extended by:
ko.extenders.percent = function(target) {
var raw = ko.observable();
var result = ko.computed({
read: function() {
var value = target();
if (value.toString().indexOf('%')===-1){
raw(parseFloat(value));
value = value + '%';
return value;
} else {
value = value.replace('%','');
raw(parseFloat(value));
value = value + '%';
return value;
}
},
write: target
}).extend({notify:'always'});
result.raw = raw;
return result;
};
So, what happens here, is that the first character input by the user formats correctly, the second character input by the user disappears, and the third joins the first and formats correctly. This happens the same if the field is computed or a regular observable, and the computed code is working fine without the extension applied. So to input 77% you would have to type 7 - X - 7 (where X can be any value since it gets lost to the process somewhere).
It should also be noted that I am using a virtual javascript numeric keyboard in this app so I am adding values via javascript (though this has not affected any of the other functionality, so I'm not sure why it would here).
Can anyone offer suggestions on what I'm doing wrong? What am I missing that is causing the input to be so buggy? I'm really determined not to ditch this notion of real-time input formatting as it makes for much cleaner presentation, but I if I have to I'll just format on blur.
Thanks in advance for any suggestions.
Because it's tricky to position the cursor properly when the formatting function replaces what you're typing as you type, I'd recommend having a field that has two modes: one where you're typing in it, and the other where it's displaying the formatted value. Which displays depends on cursor focus.
A working example is here: http://jsfiddle.net/q473mu4w/1/