Currency Format with Knockout

2019-07-25 04:05发布

问题:

I know that it's been answered before and here's the code for it (Knockout JS)

ko.observable.fn.withCurrencyFormat = function (precision) {
    var observable = this;
    observable.formatted = ko.computed({
        read: function (key) {
            return '$' + (+observable()).toFixed(precision);
        },
        write: function (value) {
            value = parseFloat(value.replace(/[^\.\d]/g, ""));
            observable(isNaN(value) ? null : value); // Write to underlying storage 
        }
    });

    return observable;
};

But how can I handle these scenarios?

  1. User deletes the 0.00 in the text field, it should default back to 0.00 instead of staying blank
  2. User types letters in the text field, it should also default back to 0.00 instead of returning NaN

回答1:

In your read function, which generates the output, the NaN is created here:

+observable() // The + tries to "cast" the observable's value to a number

To get rid of the NaN, you'll have to do an isNaN check:

var nr = +observable();
if (isNaN(nr)) {
  nr = 0;
}

Now, in your write method, which transforms the input, there's a null value returned for invalid input. Replace this to 0 to default to $0.00:

observable(isNaN(value) ? 0 : value);

If you can be sure the formatted computed is the only one writing to the underlying observable, you only need to fix one of these (i.e. you decide to format values on inputting them to the system or on outputting them).

The snippet below shows these fixes linked to an input. Personally, I think this behavior is better suited for an extender, but I'm not sure if it matters.

ko.observable.fn.withCurrencyFormat = function (precision) {
    var observable = this;
    observable.formatted = ko.computed({
        read: function (key) {
          var nr = +observable();
          if (isNaN(nr)) nr = 0;
          
          return '$' + nr.toFixed(precision);
        },
        write: function (value) {
        
            value = parseFloat(value.replace(/[^\.\d]/g, ""));
            observable(isNaN(value) ? 0 : value);
        }
    }).extend({notify: 'always'});

    return observable;
};

var obs = ko.observable(0).extend({notify: 'always'});
var val = obs.withCurrencyFormat(2).formatted;

ko.applyBindings({
  val: val
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<input data-bind="value: val">



标签: knockout.js