Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Extenders in Knockout JS not working

Just finding my way in KO, so please be gentle!

Individually each extender works, but when i chain them, the first one (reset) doesnt fire.

Javascript:

ko.extenders.reset = function (target) {
    var initialValue = target();

    target.reset = function () {
        target(initialValue);
    }

    return target;
}
ko.extenders.numeric = function (target, precision) {
    //create a writeable computed observable to intercept writes to our observable
    var result = ko.computed({
        read: target, //always return the original observables value
        write: function (newValue) {
            var current = target(),
                roundingMultiplier = Math.pow(10, precision),
                newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
                valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;

            //only write if it changed
            if (valueToWrite !== current) {
                target(valueToWrite);
            } else {
                //if the rounded value is the same, but a different value was written, force a notification for the current field
                if (newValue !== current) {
                    target.notifySubscribers(valueToWrite);
                }
            }
        }
    }).extend({
        notify: 'always'
    });

    //initialize with current value to make sure it is rounded appropriately
    result(target());

    //return the new computed observable
    return result;
};

function AppViewModel(first, last) {
    this.firstName = ko.observable(first).extend({
        reset: true

    });
    this.lastName = ko.observable(last).extend({
        reset: true,
        numeric: 0
    });
    self.resetAll = function () {
        for (key in self) {
            if (ko.isObservable(self[key]) && typeof self[key].reset == 'function') {
                self[key].reset()
            }
        }
    }
}

ko.applyBindings(new AppViewModel());

HTML:

1 extender (works):<input data-bind='value: firstName' /><br>
2 extenders (doesnt work)<input data-bind='value: lastName' /><br>
<input type="button" value="Reset All" data-bind="click:resetAll" id="ResetInvoiceButton" />

Fiddle:

http://jsfiddle.net/sajjansarkar/vk4x2/1/

like image 996
Sajjan Sarkar Avatar asked Dec 30 '13 00:12

Sajjan Sarkar


1 Answers

Because your numeric extender returns a new computed the order of your extenders does matter.

In your current setup your reset extender runs first and it adds the reset function to your original observable but then the numeric runs so it overrides your "reset enhanced" observable with a completely new computed observable.

So you just need to execute your extenders in the correct order:

this.lastName = ko.observable(last)
                  .extend({ numeric: 0 })
                  .extend({ reset: true });

Demo JSFiddle.

Note that if you want to have a specific order for your extenders you need to apply them in separate extend calls otherwise the execution order is not guarantied to be in the order of the properties.

like image 91
nemesv Avatar answered Sep 20 '22 14:09

nemesv