havardhu
havardhu

Reputation: 3616

Knockout string format pattern

In WPF there is a binding that I use a lot;

<GridViewColumn DisplayMemberBinding="{Binding Path=Price, StringFormat=Now {0:c}!}"/>

Is there a good way to achieve a similar binding in knockout? I'm using a sprintf library which would be great to utilize.

I guess I can create a custom binding for this, but this should be a rather common request so I thought I'd check here before trying to re-invent the wheel.

One use case is to build a href attribute of an atag dynamically, e.g. to produce something like this:

<a href="#products/1/product/2">Foo</a>

Where 1 is the product group and 2 is the id of a product

Upvotes: 2

Views: 3700

Answers (1)

manji
manji

Reputation: 47978

Because you want to format a value for display (ui) and to follow its changes, a custom binding that calls your sprintf library is the most suitable solution, which offers reusability also, for example:

ko.bindingHandlers.sprintf = {
    update: function(element, valueAccessor) {
        var options = valueAccessor();
        var formatted = sprintf(ko.unwrap(options.format), 
                                ko.unwrap(options.args).map(function(arg) {
                                    return ko.unwrap(arg);
                                });
        if(options.attr) {
            element.setAttribute(options.attr, formatted);
        } else {
            element.textContent = formatted;
        }
    }
}

where this custom binding require a config object having the following properties:

  • attr: the attribute to update (null if the text content of the element is to update)
  • format: string format
  • args: format args

Usage:

<a data-bind="sprintf: { attr:'href', 
                         format:'#products/%0/product/%1', 
                         args: [val1, val2] }">
    click
</a>
// val1 & val2 are ko observables

But you can also use sprintf directly within the data-bind:

<a data-bind="attr: { href: sprintf('#products/%0/product/%1', 
                                    [val1(), val2()]) 
                    }">
    click
</a>

Demo: JSFiddle

Upvotes: 5

Related Questions