Knockout bindingHandler for comma separated numbers

I am creating a very multi-fertile application in KnockoutJS, and I want to be able to format large numbers so that they are separated by commas and beautiful on the eye (xxx, xxx).

As you will see from the scripts below, I have this by wrapping the bound value inside the format function with a simple RegEx, but the problem is that it overwrites the value inside the input and inserts ',' into the base value.

Larger numbers are used later in the application, so to prevent NaN errors, I had to assign a data attribute to an input value containing an unsigned "," value, and this value is stored in sessionStorage.

I feel like I have greatly inflated my HTML markup and believe that what I want to achieve is possible with bindHandler, but my binding handler is not quite there.

Fiddle: http://jsfiddle.net/36sD9/2

formatLargeNumber = function (number) { if (typeof (number) === 'function') { return number().toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } } ko.bindingHandlers.largeNumber = { init: function(element, valueAccessor) { var value = ko.unwrap(valueAccessor()); var interceptor = ko.computed({ read: function() { return formatLargeNumber(value); }, write: function(newValue) { value(reverseFormat(newValue)); } }); if(element.tagName == 'input' ) ko.applyBindingsToNode(element, { value: interceptor }); else ko.applyBindingsToNode(element, { text: interceptor }); } } 

Any ideas?

+7
javascript jquery
source share
1 answer

You have a few problems with your current approach:

  • element.tagName returns INPUT, etc., so you need to take care of the case when conducting the comparison.

  • var value = ko.unwrap(valueAccessor()); you expand your observable, so when calculating you use its value, not a function. So you just need var value = valueAccessor(); , and you need to call ko.unwrap in the computed read method.

  • You don't need to just format, but you need to "unformat" in the write method, but your formatLargeNumber only does the format.

  • You applied value and your largeNumber on the same input, which interferes with two connections to each other

  • Do not write the formatting code yourself, just use the library that already does this: http://numeraljs.com/

So here is the adjusted version of your binding using numeraljs:

 ko.bindingHandlers.largeNumber = { init: function(element, valueAccessor) { var value = valueAccessor(); var interceptor = ko.computed({ read: function() { return numeral(ko.unwrap(value)).format('0,0'); }, write: function(newValue) { value(numeral().unformat(newValue)); value.valueHasMutated(); } }).extend({notify: 'always'}); if(element.tagName.toLowerCase() == 'input' ) ko.applyBindingsToNode(element, { value: interceptor }); else ko.applyBindingsToNode(element, { text: interceptor }); } } 

And use it as follows:

 <input data-bind="largeNumber: testVal"> 

JSFiddle demo.

+12
source share

All Articles