JSFiddle - React, Tailwind, and code Playground
HTML
<script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/cupertino/jquery-ui.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<!DOCTYPE html>
<html>
<head>
</head>
<body class='ui-widget'>
<header class='ui-widget-header'>
<h1>Give me all of your money</h1>
</header>
<div class='ui-widget-content'>
<p>
<label>How Much?</label><input data-bind="money:Cash" /></p>
<p>
<label>Non inputs too!</label><span data-bind="money:Cash" /></p>
<p>
<label>Normal binding:</label><span data-bind="text:Test" /></p>
</div>
</body>
</html>
CSS
.money {text-align:right}
.money.negative{color:#f00}
JavaScript
(function ($) {
var cleanInput = function (value) {
return parseFloat(value.replace(/[^0-9.-]/, ''));
}
var formatInput = function (value) {
toks = value.toFixed(2).replace('-', '').split('.');
var display = $.map(toks[0].split('').reverse(), function (elm, i) {
return [(i % 3 == 0 && i > 0 ? ',' : ''), elm];
}).reverse().join('') + '.' + toks[1];
return value < 0 ? '(' + display + ')' : display;
}
ko.bindingHandlers.money = {
init: function (elm, valueAccessor) {
$(elm).change(function () {
valueAccessor()(cleanInput(elm.value));
}).addClass('money');
},
update: function (elm, valueAccessor, allBindingsAccessor) {
var value =ko.utils.unwrapObservable(valueAccessor())
$elm = $(elm),
method = $elm.is(":input") ? "val" : "html";
$elm[method](formatInput(value)).toggleClass('negative', value < 0);
}
};
})(jQuery);
//Not part of the custom binding, just wiring the viewModel up to the bindings.
$(function(){
var ViewModel = function() {
var self = this;
self.Cash = ko.observable(1234.56);
self.Test = ko.pureComputed(function() {
return (self.Cash() * 10).toFixed(0);
});
}
ko.applyBindings(new ViewModel());
});