0

See the following code snippet:

ko.bindingHandlers.currencyFormat = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

        ko.utils.registerEventHandler(element, 'keyup', function (event) {
            var observable = valueAccessor();
            debugger;
            observable(formatInput(element.value));
            observable.notifySubscribers(5);
        });

    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).val(value);
    }
};

I've been experiencing some problems I am unable to understand why in relation to instances in which I base myself for the extensor knockout FormatCurrency plugin. When I insert the value in the field to be formatted in the change event (which would be to update the value of the field to the value entered) the error is occurring "number is not a function", because as I have seen in debugging, indeed variable "observable" that is created by valueAcessor is a number (this case is 0):

But seeing the example in which I mirrored me, the variable "observable" is not numeric, as can be seen below:

function d(){if(0<
arguments.length)return d.Pa(c,arguments[0])&&(d.X(),c=arguments[0],d.W()),this;a.k.Jb(d);return c}

Anyone have any idea what the problem might be seeing this piece of code?

The html code:

<input id="valorRealizado" class="form-control" data-bind='currencyFormat: ValRealizado' />

I'll try to better explain the scenario. In my application I will load a list of objects, in this case would be the "Andamentos" object. This list of objects comes from my Controller (I'm working with Asp.NET MVC4). The list may come empty or not. In the client-side application, can add (by "viewModel.Andamentos.push ({...})") more items to the list one by one, and save each item individually. Technically I only work with that object twice, to load it (through "viewModel.Andamentos (result.Andamento);") when I add more elements to "Andamentos".

1 Answers1

1

valueAccessor is a function that wraps what you pass to the custom binding.

If you pass an observable:

<div data-bind="currencyFormat: myProperty"></div>

==> valueAccessor = function() { return myProperty; }
    valueAccessor() is the observable

If you pass the value of the observable:

<div data-bind="currencyFormat: myProperty()"></div>

==> valueAccessor = function() { return myProperty(); }
    valueAccessor() is the value of the observable

As a side note, a good practice in custom bindings when the value wrapped in valueAccessor is needed is to call:

ko.unwrap(valueAccessor())
// valueAccessor() returns the value/observable depending on custom binding input
// ko.unwrap() will return the value if it has it already, otherwise will
// execute the observable to get the value.
manji
  • 47,442
  • 5
  • 96
  • 103
  • I appreciate your comment. In short, to my variable "observable" function as the variable example, what I need to do? I changed the code by adding "ko.unwrap (valueAccessor)" and nothing changed. – Victor Vasconcelos Dec 04 '14 at 14:24
  • I'm using the example of http://stackoverflow.com/questions/9160446/is-it-possible-to-use-knockoutjs-with-a-masked-input/17479064#17479064, using jquery.formatCurrency – Victor Vasconcelos Dec 04 '14 at 14:26
  • Could you add to your question how do you use this custom binding in html? – manji Dec 04 '14 at 14:29
  • notice it's `ko.unwrap (valueAccessor())` not `ko.unwrap (valueAccessor)` as you said. That difference is important. – Milimetric Dec 04 '14 at 14:37
  • Seeing your html, that should work ([jsfiddle](http://jsfiddle.net/2qa04wwp/1/)). In your viewmodel, `ValRealizado` is a `ko.observable`? Is it being overwritten by a static value somewhere? – manji Dec 04 '14 at 14:41
  • ValRealizado is not observable, see: Andamentos: ko.observableArray(ko.utils.arrayMap(initialDataAndamento, function (Andamento) { return { Id: Andamento.Id, IdMeta: Andamento.IdMeta, DataReferencia: Andamento.DataReferencia, ValRealizado: Andamento.ValRealizado, DscObservacao: Andamento.DscObservacao, Tendencia: Andamento.Tendencia }; })) I use this for "push" new items on the grid. – Victor Vasconcelos Dec 04 '14 at 14:46
  • If you don't supply an observable, how do you expect it to behave like an observable. I don't know for other properties, but you should at least create an observable for `ValRealizado`: `..., ValRealizado: ko.observable(Andamento.ValRealizado),...`. – manji Dec 04 '14 at 15:00
  • 1
    By the way, add the js mapping code to your question, so that all elements are there to understand it. – manji Dec 04 '14 at 15:01
  • @manji i need small clarification after loading when i change a value to '1.9' `update` fires 1st later on `keyup`then again `update` is it the way it goes ?. i'm asking because i can see a updated value on initial hit of update ? and y again it need to go to init `keyup` – super cool Dec 04 '14 at 15:08
  • 1
    That's because `observable(formatInput(element.value))` will notify subscribers and `update` is one of them and `observable.notifySubscribers(5);` will do the same. So `update`is invoked twice.The last one is not needed unless you have a reason. – manji Dec 04 '14 at 15:22
  • @manji, that part I posted is the only relevant part that relates to what I'm needing. Even putting the elements as observable, didn't work. Andamentos: ko.observableArray(ko.utils.arrayMap(initialDataAndamento, function (Andamento) { return { Id: ko.observable(Andamento.Id), IdMeta: ko.observable(Andamento.IdMeta), DataReferencia: ko.observable(Andamento.DataReferencia), ValRealizado: ko.observable(Andamento.ValRealizado), DscObservacao: ko.observable(Andamento.DscObservacao), Tendencia: ko.observable(Andamento.Tendencia) }; })) – Victor Vasconcelos Dec 04 '14 at 16:52