0

I am wondering whether there is a reason to prefer a prototype function / viewModel function over the other.

Say you wanted to represent an integer 1234 as a money value like 12.34€

What I did was, create a prototype function on the Number object:

Number.localeSeparator = 1.1.toLocaleString().substr(1, 1);

Number.prototype.centToEuro = function (separator_string) {
    if (!separator_string) {
        separator_string = Number.localeSeparator;
    }
    return (this / 100).toFixed(2).replace(".", separator_string) + "€";
}

var vm = {myMoney: ko.observable(1234)};
ko.applyBindings(vm);

This made the data binding fairly easy, because all I needed to do in the view was this:

<div data-bind="text: myMoney().centToEuro()"></div>

But instead of a prototype function, I could also create a viewModel function with almost the same code, like so:

var vm = {
    myMoney: ko.observable(1234),
    localeSeparator: 1.1.toLocaleString().substr(1, 1),
    centToEuro: function (value_int, separator_string) {
        if (!separator_string) {
            separator_string = vm.localeSeparator;
        }
        return (value_int / 100).toFixed(2).replace(".", separator_string) + "€";
    }
}
ko.applyBindings(vm);

Used in the view, it would look like this:

<div data-bind="text: centToEuro(myMoney())"></div>

As you can tell, the two HTML lines are almost exactly the same length and only vary in the approach. So the question is, which approach is to prefer?

jaySon
  • 795
  • 2
  • 7
  • 20

2 Answers2

3

Given that centToEuro has nothing to do with arbitrary numbers, but with the particular model for money you are dealing with here, and that you should not extend the builtin prototype objects, go for the viewmodel function.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Alright, makes sense. And if someone wanted to use custom functions for arbitrary numbers? Can a general statement be made on that or is it dependent on the use-case whether or not to extend the prototype? – jaySon Jun 04 '16 at 16:31
  • In that case, it's still generally considered a [bad idea](http://stackoverflow.com/q/10197174/1048572) (see also the links in the comments there). – Bergi Jun 04 '16 at 16:39
1

Isn't the meaning of your question, where to put this kinda function?

Consider using extenders, for tasks like currency formatting and so on, where you set-up once and use everywhere. Just an example:

ko.extenders.currency = function (target, option) {
    target.amount = function () {
        var amt = ko.unwrap(target);
        var localeSeparator = 1.1.toLocaleString().substr(1, 1);
        switch(option) {
            case "Eur":
                amt = (amt / 100).toFixed(2).replace(".", localeSeparator) + "€";
                break;
            default:;
            }
        return amt;
    };
    return target;
};

View Model:

myMoney: ko.observable("1234").extend({currency: "Eur"})

Markup:

<div data-bind="text: myMoney.amount()"></div>
deblocker
  • 7,629
  • 2
  • 24
  • 59
  • This answer is actually very helpful for that particular issue, thumbs up for that. But my question was really, which is considered a better practice, e.g. for helper functions (as in this case). Independent from the MVVM pattern (and Knockout), I simply do not know why I should prefer one approach over the other, since none seem to cost performance, space, stability or something. – jaySon Jun 04 '16 at 20:18