http://stackoverflow.com/questions/42030918/how-do-i-make-a-knockout-custom-binding-for-textboxes-that-formats-numbers (with value entry prevention)

by jlspake

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-debug.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
<div>

  <label>User value: </label><span data-bind="text: marketRate"></span>
  <br/>  <br/>
  <label>Safe value: </label><span data-bind="text: safeMarketRate"></span>
  <br/>  <br/>
  <label>Formatted: </label>
  <input type="text" data-bind="numericValue: marketRate, precision: 2" />
  
</div>

JavaScript

var viewModel = function(){
	var self = this;    
  self.isSelected = ko.observable(true);
  self.marketRate = ko.observable(5.01).extend({
        required: { message: 'Required', onlyIf: function() { return self.isSelected(); }},
        min: { params: 0, onlyIf: function () { return self.isSelected(); } },
        max: { params: 999999.99, onlyIf: function() { return self.isSelected(); } },
        pattern: { message: 'Maximum 2 decimal places', params: /^\d*(\.\d{1,2})?$/, onlyIf: function () { return self.isSelected(); } }
    });  
  self.safeMarketRate = ko.observable(self.marketRate());
  self.marketRate.subscribe(function(value){
  	if(self.marketRate.isValid()){
    	self.safeMarketRate(value);
    }
  });
  
  return self;
}

ko.bindingHandlers.numericValue = {
		init: function (element, valueAccessor, allBindings) {
      var valueObservable = valueAccessor();

      ko.utils.registerEventHandler(element, "change", function () {
        	valueObservable($(element).val());
      });
		},
  	update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor()),
            precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericValue.defaultPrecision;
				
        if(valueAccessor().isValid()){
        	var formattedValue = '';
          if (value) {
              if (typeof value === "string") {
                  value = parseFloat(value);
              }
              formattedValue = value.toFixed(precision);
          } else {
              value = 0;
              formattedValue = value.toFixed(precision);
          }
        	$(element).val(formattedValue);
        }else{
          $(element).val(value);
        }
        
    },
    defaultPrecision: 1
}


ko.validation.init();
ko.validation.makeBindingHandlerValidatable('numericValue');
ko.applyBindings(new viewModel());