Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good pattern to preserve custom properties created in a Knockout extension?

I currently have two Knockout extension functions. One adds a member to the Observable while the other intercepts the read and write operations.

When combining the extension methods the order of application has an unwanted effect.

Simplified code examples below.

ko.extenders.format = function(target) {
    var result = ko.computed(function(){
        return "$" + target();
    });

    target.formatted = result;

   return target;
};

ko.extenders.numeric = function(target, precision) {
    var result = ko.computed({
        read: function() {
            var current = parseFloat(target());
           return current.toFixed(precision);
        },
        write: function(newValue) {
            newValue = parseFloat(newValue);
            target(newValue.toFixed(precision));
        }
    });

    return result;
};

In the numeric method I can check for the formatted member and assign it to the new computed but I don't want to give it knowledge of the other method. This also won't be maintainable if I decide to add more members off the observable or extensions.

if(target.hasOwnProperty("formatted")){
    result.formatted = target.formatted;
}

Heres a fiddle without the hasOwnProperty fix. http://jsfiddle.net/gs5JM/2/

Notice that MyValue4 - Format: is blank due to the order of extender application and the loss of the formatted member.

Is there a better pattern to achieve the same end result and make the code more flexible?

like image 888
Sam R Avatar asked Nov 11 '22 20:11

Sam R


1 Answers

The problem is that your format extender refers to original observable and numeric creates a new one. So format and numeric work with completely different observables. Looks like you should consider to return original observable in both cases.

I would rewrite your numeric this way:

ko.extenders.numeric = function(target, precision) {

    ko.computed(function(){
        var current = parseFloat(target());
        target(isNaN(current) ? 0 : current.toFixed(precision));
    });

    return target;
};

Anonymous computed will create a subscription to target value changes with immediate evaluation. The evaluation function will try to parse a value and reassign precised numeric value to the target observable.

http://jsfiddle.net/gs5JM/3/

Note: You should not care about possible circular dependency because KO will not re-evaluate computed while it's already evaluating.

like image 109
Rango Avatar answered Nov 15 '22 03:11

Rango