Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best approach for value conversion in KnockoutJS?

I have been trying to figure out the right approach to displaying/editing percentage values in Knockout-JS (and more generally how I should create reusable components like these).

My ViewModel has an observable value which is a percentage stored as a fractional number, e.g. 0.5 to represent 50%. I would like to display and edit the value in the percentage format (e.g. '50') so the users don't get confused (they get confused easily).

writeable computed

I was able to a simple version by setting up a writeable computed function: see http://jsfiddle.net/Quango/fvpjN/

However, this is not very re-usable, as it would need to be reimplemented for each value. I experimented with an extender but this effectively masked the underlying value and so made it unusable.

BindingHandlers

I think what I need is a binding handler, so instead of writing

<input data-bind="value: commission" /> 

I would write

<input data-bind="percentage: commission" />

I had a look at the code in the "value" bindingHandler in knockout.js, but there is a lot of code there for the binding and I don't want to replicate that.

So my questions are:

  1. is there a good/standard/template way to do this sort of value conversion?

  2. if not, is there a way to re-use the "value" binding without having to copy and paste the existing code?

like image 761
Quango Avatar asked Jan 31 '13 17:01

Quango


1 Answers

I always wanted to write an extender. So here comes another answer to your question that is implemented via a knockout extender.

I'm still undecided wether I like this one or the one with the Percentage class better.

HTML

<input data-bind="value: p1.percentage, valueUpdate: 'afterkeydown'"></input>%
= <span data-bind="text: p1"></span>

JavaScript

ko.extenders.percentage = function(target, option) {
    target.percentage = ko.computed({
        read: function() {
            return this() * 100;
        },
        write: function(value) {
            this(value/100);
        },
        owner: target
    });
    return target;
};

var model = {
    p1: ko.observable(0.5).extend({'percentage': true})
}

ko.applyBindings(model)

Live demo

http://jsfiddle.net/DWRLr/

like image 117
bikeshedder Avatar answered Nov 12 '22 02:11

bikeshedder