0

I have a TextBox which is bind to a knockout model. Now, in the TextBox user can enter the cost like "0.00", "4.95" etc. But they can also enter the dollar sign like this: "$50.00" and "$6.00".

When the user enters the dollar sign the model breaks since it expects a decimal value. I was wondering if there is someway I can remove the dollar sign inside the data-bind expression below:

<input type="text" id="cost" data-bind="value: selectedChoiceValue" />
john doe
  • 9,220
  • 23
  • 91
  • 167

5 Answers5

0

Try escaping the $ in the string.

Example:

\$5.00
Korgrue
  • 3,430
  • 1
  • 13
  • 20
0

var price = $("#cost").val().replace("$", "");

But it should be noted that the data attribute is read-only. Meaning if you update the value in the data attribute after page load and then try to retrieve it via $("#cost").data("bind") it will not return the updated value.

If you must modify then retrieve an updated data attribute, you have to use .attr("data-bind")

0

You could also use

var without_dollar_sign = $("#cost").val().replace(/\$/g, '');
$("#cost").val(without_dollar_sign)
0

Bind the field to a writable computed. If the validation is successful, write the new value to your numeric observable; if not, do some error handling. The read component of your computed can do some formatting or not, as you like.

function toNumber(stringValue) {
  if (stringValue[0] == '$') {
    stringValue = stringValue.substr(1);
  }
  var result = parseFloat(stringValue);
  return result;
}

vm = {
  cost: ko.observable(0),
  costAsString: ko.pureComputed({
    deferEvaluation: true,
    read: function() {
      return '$' + vm.cost();
    },
    write: function(newValue) {
      var numberValue = toNumber(newValue);
      if (isNaN(numberValue)) {
        alert('Invalid number');
        var revert = vm.cost();
        vm.cost('');
        vm.cost(revert);
      } else {
        vm.cost(numberValue);
      }
    }
  })
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" id="cost" data-bind="value: costAsString" />
<div>Value is: <span data-bind="text: cost"></span>
</div>
Roy J
  • 42,522
  • 10
  • 78
  • 102
0

Honestly, I think the best way is to just user an html5 number input field:

<input type="number" id="cost" data-bind="value: selectedChoiceValue" />

If you want a knockout solution, You could use an observable/computed combo like Roy J's answer, or you could use a single observable and subscribe and trottle:

var vm = function(){
  this.selectedChoiceValue = ko.observable('');
  
  // Just to make sure things do go crazy
  this.selectedChoiceValue.extend({ rateLimit: 10 }); // in ms
  
  this.selectedChoiceValue.subscribe(function(newValue){
    // Assuming you'll want to also parse out other invalid characters
    newValue = yourFunctionToParseTheInput(newValue);
    
    // Update this value to be the parsed valued 
    this.selectedChoiceValue(newValue);
  
  }, this);
}

function yourFunctionToParseTheInput(value) {
  return value.replace('$', '');
}

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<span class="currency">$<input type="text" id="cost" data-bind="value: selectedChoiceValue, valueUpdate:['afterkeydown']" /></span>

Restricting input to textbox: allowing only numbers and decimal point has some good ways to parse the input value as well.

Community
  • 1
  • 1
TheRightChoyce
  • 3,054
  • 1
  • 22
  • 19