Paul Aldred-Bann
Paul Aldred-Bann

Reputation: 6020

Update observableArray only on event

Example jsFiddle


Note: I'm currently learning with KnockoutJS so any guidance on best practices, or corrections on whether I'm doing things right are always appreciated!

I am working on a test project trying to get to grips with the brilliant KnockoutJS and I'm now at a point where I need to think about deferring the update of my observableArray. I have a view model of items (which I'm retrieving via an AJAX call), and a table that lists them. When I click on an item, a modal pops up populated with the details and allows me to edit them. Let's just call them items for now, here's the definition.

var itemViewModel = function (id, name) {
    this.Id = ko.observable(id);
    this.Name = ko.observable(name);
};

When I click on the item, I set a selectedItemId and then loop through my items looking for the correct one, when found I set it to selectedItem and show the modal.

var targetItem = ko.utils.arrayFirst(self.items(), function (current) {
    return current.Id() === self.selectedItemId();
});
self.selectedItem(targetItem);

All working perfectly so far, but my observableArray is getting updated irrespective of whether I click Close or Save in the modal. Now, I'm aware this is correct behavior, but my question is: how do I update my observableArray ONLY when I click Save?

Here's how I think I should be doing it (but I'm not entirely sure whether I'm correct).

I should have a non-observable version of itemViewModel (still extracted from the items collection as before, but without the observables) and then call some event when I click Save on the modal that replaces the item in the observableArray like so:

self.items.replace(oldItem, newItem);

While the above does seem logical, I'm not sure if it makes full use of KnockoutJS or not. The main thing that irks me about the above, is having to have the non-observable version of itemViewModel, can I not just unsubscribe or dispose the tracking?

Upvotes: 2

Views: 225

Answers (1)

Paul Aldred-Bann
Paul Aldred-Bann

Reputation: 6020

Solution jsFiddle


A huge thanks to the article provided by nemesv, which gave me all I need to do exactly what I wanted to do! For anyone else stumbling on this with the same question, here's what I did.

I used the protectedObservable that was defined in this article and followed his example of committing and rolling back changes. So I defined my itemViewModel like this:

var itemViewModel = function (id, name) {
    this.Id = ko.protectedObservable(id);
    this.Name = ko.protectedObservable(name);
    this.commit = function () {
        this.Id.commit();
        this.Name.commit();
    };
    this.rollback = function() {
        this.Id.reset();
        this.Name.reset();
    };
};

Then applied the same two commit and rollback methods to my overall view model (which just invoke the $parent.commit and $parent.rollback methods on the event of clicking Save like this:

var viewModel = function (items) {
    var self = this;
    self.items = ko.observableArray(items);
    self.selectedItemId = ko.observable();
    self.selectedItem = ko.observable();
    self.selectItem = function () {
        var targetItem = ko.utils.arrayFirst(self.items(), function (current) {
            return current.Id() === self.selectedItemId();
        });
        self.selectedItem(targetItem);
        $('#edit-item-modal').dialog('open');
    };
    self.commit = function () {
        self.selectedItem().commit();
        $('#edit-item-modal').dialog('close');
    };
    self.rollback = function () {
        self.selectedItem().rollback();
        $('#edit-item-modal').dialog('close');
    };
};

I really like this solution, so thanks again to nemesv for the information!

Upvotes: 1

Related Questions