Knockout.js Money Observable

A few days ago I posted a solution to create a custom money binding for knockout.js. If you recall, I was a bit hesitant about the solution because I felt that it wasn't very semantic. Namely, DOM objects do not have a money property to bind to. I had a chat with Elijah Manor and he shared the same reservations. Comments on that post echoed the yucky feeling. Time for round 2.

See the full sample on jsFiddle

What I had missed was the writable dependentObservable introduced in knockout.js some time recently. With this new found power I can keep the appropriate text or value bindings and still have a clean view model. With the solution above, I don't have to jump through hoops to get a clean json representation of my view model. On top of that, my bindings are still simple enough to understand. There is less magic and I like it that way.

This feels a lot better than the first solution. I'm still not sold though. It feels like this type of concern should be pushed out of the view model. Possibly something like this? <input data-bind="value:Cash" data-convert="value:MoneyConverter" />

What do you think of the new bits? Is this a better or worse solution? Also, how can we improve this?

  • Ryan Niemeyer

    I like the encapsulation in this solution. I use extended observables quite often for a variety of purposes and find them extremely useful.

    There are some advantages to having this type of functionality in the view model. Changes that are made by user input or programmatically will both be handled in the same way. Also, in some cases it allows your view to remain as simple (dumb) as possible.

    However, I was thinking a little bit about possible approaches to keeping the formatting logic separate from both the view model and the bindings. It would be interesting if bindings looked for an additional “formatter” binding that could be used to format/deformat the value. Here is a sample that I was playing with where I have “formattedText” and “formattedValue” bindings that wrap the regular bindings and apply a specified formatter using a dependentObservable.

  • Ryan Niemeyer

    Steve layed out a roadmap to KO 1.3 today here: It includes the idea of “extenders” for observables. This could be an interesting concept for your example. Additionally, if you want to have the view declaratively control the formatting, then my bindings from above could likely be slightly simplified to apply an extender to the observable (from valueaccessor).

  • wilsonhut
  • Steve Sanderson

    Hey, nice work!

    I agree with Ryan and think that both of your solutions are perfectly good. I’d say either approach could be preferable, depending on how you want to structure your view model.

    [A] If you think of the underlying data as being just a number, and want to binding it to multiple parts of your UI, and in some places it should be represented as currency (perhaps with special UI logic, like a popup to choose between USD and GBP, say) and in other places represented in other ways, then it makes sense for the currency transformations to be encapsulated in the binding. That’s because, with this line of thought, it is just an aspect of how the data is mapped into the UI, which is exactly the role that bindings play. You can implement arbitrary currency-specific UI behavior in that binding.

    [B] Or, if you think of the underlying data as being currency, and it will only ever be seen that way, then it makes sense to define a “moneyObservable” as you have done here, and use the regular “text”/”value” bindings to attach it to the UI, with no additional UI behaviors.

    The way I’ve found most flexible to handle this particular scenario is actually to do both: to have an explicit “raw value” observable on my view model, plus a “formatted value” dependent observable connected to it. That way I can bind either the raw data or the formatted data, and I can use it with any of the built-in bindings, and if I want custom UI behaviors, I can create a custom binding that accesses the data in either or both formats.

    Here’s an example:

    It’s pretty similar to your solution, except that the view model exposes both views of the data. Also, the formatting code handles arbitrary edits in the text boxes.

  • Peter

    I’d be interested to know what you think about this ( as an approach.

    On the plus side it avoids creating custom formattedText, formattedValue, formattedWhateverElse bindings. On the downside it’s creating a dependent observable every time a value changes.

  • puppies for sale in miami

    I have read several good stuff here. Definitely price bookmarking for revisiting.

    I wonder how a lot effort you set to create one of these magnificent
    informative web site.

  • Enis Pilavdzic

    Thanks for sharing this Peter!

    I found your approach to be simple and flexible, and it works better for me for certain things than even newer approaches like extended observables.

  • Brandon Wittwer

    I’ve made a few improvements but I’m not certain how “clean” the approach is. My additions change this to an extender, fix an issue with the regexp, handle the scale of the decimal number, as well as allows for null instead of always defaulting to 0.

  • Brandon Wittwer

    Hey Ryan, see my reply above and offer any advice you can on how to simplify some of the logic. Seems twisty at times.