When I bind numeric data in my view model using knockout, it displays correctly but changes the data type to string if the user changes the input tag value. The problem with submitting string is that the server expects a numeric value with no implicit conversion available.
Any way to tell knockout to maintain the data type of the original property value?
My example code that matches the view model names to the input tag names. I use unobtrusive knockout to do the bindings, which works fine.
// Bind the first object returned to the first view model object
// FNS is the namespace, VM is the view model
FNS.VM.Items[0] = ko.mapping.fromJS(data.Items[0]);
// For each property found, find the matching input and bind it
$.each(FNS.VM.Items[0], function (indexInArray, valueOfElement) {
var attrName = indexInArray;
var attrValue;
if (typeof valueOfElement == "function")
attrValue = valueOfElement();
else
attrValue = valueOfElement;
var a = $('input[name="' + attrName + '"][type="checkbox"]');
if (a.length)
a.dataBind({ checked: 'VM.Items[0].' + attrName });
var b = $('input[name="' + attrName + '"][type="radio"]');
if (b.length)
b.dataBind({ checked: 'VM.Items[0].' + attrName });
var c = $('input[name="' + attrName + '"][type="text"]');
if (c.length)
c.dataBind({ value: 'VM.Items[0].' + attrName });
});
ko.applyBindings(FNS);
Here is a thread with a few different techniques to keep the value numeric: https://groups.google.com/d/topic/knockoutjs/SPrzcgddoY4/discussion
One option is to push this concern into your view model and create a numericObservable
to use instead of a normal observable. It might look like:
ko.numericObservable = function(initialValue) {
var _actual = ko.observable(initialValue);
var result = ko.dependentObservable({
read: function() {
return _actual();
},
write: function(newValue) {
var parsedValue = parseFloat(newValue);
_actual(isNaN(parsedValue) ? newValue : parsedValue);
}
});
return result;
};
Sample: http://jsfiddle.net/rniemeyer/RJbdS/
Another option is to handle this with a custom binding. Instead of using the value
binding, you can define a numericValue
binding and use it instead. It could look like:
ko.bindingHandlers.numericValue = {
init : function(element, valueAccessor, allBindings, data, context) {
var interceptor = ko.computed({
read: function() {
return ko.unwrap(valueAccessor());
},
write: function(value) {
if (!isNaN(value)) {
valueAccessor()(parseFloat(value));
}
},
disposeWhenNodeIsRemoved: element
});
ko.applyBindingsToNode(element, { value: interceptor }, context);
}
};
Sample: http://jsfiddle.net/rniemeyer/wtZ9X/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With