Writing back to a computed array in Knockout.js?

I have a computed property in my model that simply splits a comma-separated string into an array, and I want to be able to use a special "checked" binding function to write the changes back through the computed property.

Everything works fine for reading the computed property, but as soon as I check one of the checkboxes, I get errors about some function that doesn't support splicing (if I uncheck) or doesn't support push (if I check).

> Uncaught TypeError: Object function
> h(){if(0<arguments.length)return"function"===typeof
> v?v.apply(d,arguments):j(Error("Cannot write a value to a ko.computed
> unless you specify a 'write' option. If you wish to read the current
> value, don't pass any parameters.")),this;n||g();b.r.Wa(h);return l}
> has no method 'splice' knockout-min.js:60 (anonymous function)

      

I've created a quick jsfiddle example to illustrate what's going on. http://jsfiddle.net/Y6tXw/

var MyModel = function() {
    this.src = ko.observable("one,two");
    this.comp = ko.computed({
        read: function() {
            return (this.src() || "").split(",");
        },
        write: function(value) {
            var csvs = (value || []).join(",");
            this.src(csvs);
        },
        owner: this
    });
};

var model = new MyModel();
ko.applyBindings(model);

      

It never calls my write function. It seems to be crumbling in binders. What am I doing wrong?

+3


source to share


2 answers


comp in the above case in a computed, not an array. I have changed your code. I used subscription to listen for change notifications raised by comp and recalculated the sec value



<input type="checkbox" value="one" data-bind="{ checked: comp }"/>
<input type="checkbox" value="two" data-bind="{ checked: comp }"/>
<input type="checkbox" value="three" data-bind="{ checked: comp }"/>
<input type="text" data-bind="{ value: src }"/>


var MyModel = function () {

    var self = this;

    self.src = ko.observable("one,two");

    self.comp = ko.observableArray((self.src() || "").split(","));

    self.comp.subscribe(function () {
        self.src(ko.utils.unwrapObservable(self.comp).join(","));
    });
};

$(function () {
    var model = new MyModel();
    ko.applyBindings(model);
})

      

+4


source


The knockout assumes that you are binding to an observable array. I don't think they intended to support this option. (not yet at least) To get around this it would be easier to go the other way around. Make the array an array as well src

computed.



function ViewModel(data) {
    this.comp = ko.observableArray(["one","two"]);
    this.src = ko.computed({
        read: function () {
            return this.comp().join(",");
        },
        write: function (value) {
            this.comp(value.split(","));
        },
        owner: this
    });
}

      

+1


source







All Articles