0
votes

I'm working on a web application with knockout.js and knockout validation.

I have one view model like this:

var viewModel = {
    prop1 : ko.observable().extend({number:true}),
    prop2 : ko.observable().extend({number:true}),
    prop3 : ko.observable().extend({number:true}),
    save : function () {
        var vmValidatable = ko.validatedObservable(viewModel);
        if (!vmValidatable.isValid())
            return false;
    }
}

On front-end if I try to save one number with decimal separator comma instead of a point my save function return false.

For example: if prop1 have "1.2" value the save function work correctly else if prop1 have "1,2" value the save function return false.

Can you help me please?

Thank you a lot

1
Have you checked out the localization documentation for Knockout Validation? github.com/Knockout-Contrib/Knockout-Validation/wiki/…Steve Greatrex
Hi Steve, I've read the documentation but It talk about "display the validation messages in multiple languages"...ilMattion
Can you share the code of the number extension? It's not a default one from knockout.js, is it?user3297291
Hi, the number extension is part of knockout validation extension, if it is possibile I would not change knockout validation extension code.ilMattion

1 Answers

0
votes

Here's the source for the number extender you're using:

// https://github.com/Knockout-Contrib/Knockout-Validation/blob/master/src/rules.js#L221
ko.validation.rules['number'] = {
  validator: function (value, validate) {
    if (!validate) { return true; }
    return ko.validation.utils.isEmptyVal(value) || 
      (validate && /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value));
  },
  message: 'Please enter a number.'
};

I'm no regexp expert, but it looks like "," separated numbers are only supported when they separate 3 digits. I.e.: you cannot use commas to mark a decimal point.

console.log(/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test("100,000"))
console.log(/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test("100,000.00"))
console.log(/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test("1,2"))
console.log(/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test("1,200"))

You could add another extender to remove , characters if entered values are tested to not match the pattern. Not sure if it's a good idea though.

var test = function(val) {
  if (!val) return true;

  return /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(val);
};


ko.extenders.removeCommas = function(target, option) {
  var result = ko.pureComputed({
    read: target,
    write: function(newValue) {
      var current = target(),
        valueToWrite = test(newValue) ? newValue : newValue.replace(/,/g,
          ".");

      if (valueToWrite !== current) {
        target(valueToWrite);
      } else {
        if (newValue !== current) {
          target.notifySubscribers(valueToWrite);
        }
      }
    }
  }).extend({
    notify: 'always'
  });

  result(target());
  return result;
};

var ViewModel = function() {
  this.input = ko.observable().extend({
    removeCommas: true
  });
}

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

<input data-bind="textInput: input" />