0
votes

I'm relatively new to knockout and hitting some issues with observables. This is a paired down version of some knockout I'm using:

var model;
function viewModel(data) {
    var self = this;       
    self.favesData = ko.observableArray(data.User.Favorites);       
    self.splitRows = ko.computed(function () {
        var i = 0;
        var faveRows = [];
        var size = 2;
        while (i < self.favesData().length) {
            faveRows.push(self.favesData().slice(i, i += size));
        }
        return faveRows;
    });

    self.refresh = (function (data) {
        self.favesData(data.User.Favorites);
    });
}

function onComplete(result) {
    if (!model) {
        model = new viewModel(result);
        ko.applyBindings(new viewModel(result));
    } else {
        model.refresh(result);
    }
}

<table class="table-main link" data-bind="foreach: splitRows">
    <tr data-bind="foreach: $data">
        <td>
            <div class="link">
                <a href="#" data-bind="text: $data.Name">
                </a>
            </div>
        </td>
     </tr>
 </table>

I use an ajax GET, which calls onComplete. The data comes in just fine and everything binds great on the initial load. I then call the same ajax function with new input, which starts to work correctly - the data is returned and different, the refresh updates favesData, and splitRows recalculates, but the UI display never changes. Shouldn't splitRows update the binding when it recalculates? I'm pretty confused about how passing new data to favesData can update the computed observable that watches it, but the computed observable doesn't update the UI.

2

2 Answers

3
votes

In your onComplete method you are not binding the Markup to the model, but to a new instance of the viewModel it should be like below.

ko.applyBindings(model);

the refresh is being called on a model that is not used by the UI

0
votes

Try clearing the array and pushing the new items in, something like;

 self.favesData.removeAll();
 data.User.Favorites.each(function(fav) { self.favesData.push(fav); });

to see if that sorts it out. I tend to use the official knockout mapping plugin, which does a really good job of 'knockouting-up' models from the server, and refreshing them.

So typically you'd end up refreshing by doing something like this inside your viewmodel

self.refresh = function(data) {
    ko.mapping.fromJS(data, {}, self);
}

to re-bind the whole model.