user135498
user135498

Reputation: 6133

Knockout js binding not updating

I have a view model that contains a reference to another object and the referenced object is bound to my UI. The bindings seem to work fine when I'm adding objects to the observable array but don't seem to update when I clear the array.

I've reproduced the issue is jsfiddle and I'm wondering if someone can point me in the right direction?

http://jsfiddle.net/chriswnichols/gcywcce7/

function County(name) {
    this.Name = name;
}

function ListCriteria() {
    var self = this;
    self.States = ko.observableArray([]);
    self.Counties = ko.observableArray([]);
    self.Zips = ko.observableArray([]);
    self.Cities = ko.observableArray([]);
    self.DobRanges = ko.observableArray([]);
    self.Clear = function () {
        self.States = ko.observableArray([]);
        self.Counties = ko.observableArray([]);
        self.Zips = ko.observableArray([]);
        self.Cities = ko.observableArray([]);
        self.DobRanges = ko.observableArray([]);
    };
}

var ViewModel = function () {
    var listCriteria = new ListCriteria(),
        reset = ko.computed(function () {
            listCriteria.Clear();
        });
    return {
        listCriteria: listCriteria,
        reset: reset
    }
};
viewModel = new ViewModel();
ko.applyBindings(viewModel);

Thanks.

Upvotes: 0

Views: 1130

Answers (1)

user2864740
user2864740

Reputation: 61875

It doesn't work because new observable arrays are being created. KO binds per observable so the old observable arrays are still bound - the new (unbound) observable arrays have no way to affect the UI.

One approach is to empty out the original observable arrays. In this case that can be done with ObservableArray.removeAll:

self.Clear = function () {
    [self.States, self.Counties, self.Zips].forEach(function (arr) {
        arr.removeAll();
        // Alternative, because it updates the observable with an empty array
        // (without creating a new unbound observable)
        // arr([]);
    });
};

Another approach is to use an observable indirection layer and rebind the outer observable. This isn't necessarily called for in this case and the following section is included for completeness.

var ViewModel = function () {
    var listObs = ko.observable(new ListCriteria());
    return {
        listCriteria: listObs,
        // This probably shouldn't be a computed.. data-bind as "click: reset"
        reset: function () {
            // Assign a new value to existing (and bound) observable
            listObs(new ListCriteria());
        }
    }
}

And then it could be data-bound as foreach: listCriteria().Counties. The same approach of using an indirection observable could also be done on each array and then it would look like foreach: listCriteria.States(), albeit this is silly in this case considering that it's wrapping an observable array.

function ListCriteria() {
    var self = this;
     self.States = ko.observable(ko.observableArray([]));
     self.Clear = function () {
         // Mutate existing observable, assigning an observable as a value
         self.States(ko.observableArray([]));
     };
}

However, the solution to the problem is the same in all cases: only use mutations-of observable objects to affect the bound data.

Upvotes: 2

Related Questions